【2018】

D1T1.铺设道路(贪心)

肯定要挖至少第一个坑的深度,再把后面比现在的坑的最深深度深的差值加起来,更新现在坑得最深深度(因为比现在最深深度浅的可以和之前的一起一次性处理,只用多花时间填更深的差值)。

#include<bits/stdc++.h>
#define ll long long
#define ri register int 
#define For(i,l,r) for(ri i=l;i<=r;i++)
#define Dfor(i,r,l) for(ri i=r;i>=l;i--)
using namespace std;
int n,d,tmp;
ll ans;
inline ll read(){
    ll f=1,sum=0;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();}
    return f*sum;
}
int main(){
    n=read();
    For(i,1,n){
        d=read();
        if(d>tmp) ans+=d-tmp;
        tmp=d;
    }
    printf("%lld
",ans);
    return 0;
}
View Code

 

D1T2.货币系统(背包)

瞪眼法)发现原有的货币中能且只能保留凑不出来的币值,能被凑出来的币值都不需要保留,背包可以解决。 

#include<bits/stdc++.h>
#define ri register int
#define ll long long
#define For(i,l,r) for(ri i=l;i<=r;i++)
#define Dfor(i,r,l) for(ri i=r;i>=l;i--)
using namespace std;
const int M=25005;
const int N=105;
int T,a[N],f[M],ans,n;
inline ll read(){
    ll f=1,sum=0;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();}
    return f*sum;
}
int main(){
    T=read();
    while(T--){
        n=read();
        For(i,1,n) a[i]=read();
        sort(a+1,a+n+1);
        f[0]=1;
        For(i,1,n){
            if(f[a[i]]) continue;
            For(j,a[i],a[n]){
                f[j]|=f[j-a[i]]; 
            }
            ans++;
        }
        printf("%d
",ans);
        memset(f,0,sizeof(f));ans=0;
    }
    return 0;
}
View Code

D1T3 赛道修建(菊花图+树的直径+二分答案)

55分大众分。

D2T1.旅行(DFS+拓扑排序+基环树)

数据显然分为两种情况

1. n=m-1:一棵树,vector存每个点的子点,点的编号从小到大sort一遍保证字典序最小,最后直接在树上跑dfs即可。

2. n=m: 一棵基环树,即树上有一个环,显然环上有一条边不用跑,拓扑排序(记录出度入度,这里因为无向边所以出度入度合在一起算)标记不在环上的点,然后枚举边,如果边的两个点都在环上那么删掉这条边在树上跑一遍dfs,再比较一下字典序更新答案,然后把边加回来。

#include<bits/stdc++.h>
#define ri register int
#define ll long long
#define For(i,l,r) for(ri i=l;i<=r;i++)
#define Dfor(i,r,l) for(ri i=r;i>=l;i--)
using namespace std;
const int M=5005;
int n,m,head[M],ans[M],t,d[M],w[M][M],res[M];
struct node{
    int u,v;
}e[M<<1];
vector<int>vec[M];
bool vis[M],use[M];
inline ll read(){
    ll f=1,sum=0;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();}
    return f*sum;
}
inline void work(){
    if(!ans[1]){
        For(i,1,n) ans[i]=res[i];
        return;
    }
    For(i,1,n){
        if(res[i]>ans[i]) return;
        if(res[i]<ans[i]){
            For(i,1,n) ans[i]=res[i];
            return;
        }
    }
}
inline void dfs(int x){
    vis[x]=1;res[++t]=x;
    for(ri i=0;i<vec[x].size();i++){
        int v=vec[x][i];
        if(vis[v]||!w[x][v])continue;
        dfs(v);
    }
}
inline void topo(){
    queue<int>q;
    For(i,1,n){
        if(d[i]==1){
            q.push(i);
            use[i]=1;
        }
    }
    while(!q.empty()){
        int u=q.front(),len=vec[u].size();
        q.pop(),use[u]=1;
        For(i,0,len-1){
            int v=vec[u][i];
            d[v]--;
            if(d[v]==1){
                q.push(v);
                use[v]=1;
            }
        }
    }
}
int main(){
    n=read(),m=read();
    For(i,1,m){
        int u=read(),v=read();
        e[i]=(node){u,v};
        d[u]++,d[v]++;
        w[u][v]=w[v][u]=1;
        vec[u].push_back(v),vec[v].push_back(u);
    }
    For(i,1,n){
        sort(vec[i].begin(),vec[i].end());
    }
    if(m==n-1){
        dfs(1);
        For(i,1,n) printf("%d ",res[i]);
        return 0;
    }
    topo();
    For(i,1,m){
        int x=e[i].u,y=e[i].v;
        if(use[x]||use[y]) continue;
        w[x][y]=w[y][x]=0;
        memset(vis,0,sizeof(vis));
        t=0;dfs(1);work();
        w[x][y]=w[y][x]=1;
    }
    For(i,1,n) printf("%d ",ans[i]);
    return 0;
}
View Code

D2T2.填数游戏(打表找规律)

 数学证明显然不会也很麻烦。

这个表其实也不是很好打,跑dfs和一个判定合法与否的函数,看看代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100;int a[N][N],ans,no_ans,las;
inline void ok(int x,int y,int n,int m,int cur){
    cur<<=1,cur+=a[x][y];
    if(x==n&&y==m){
        no_ans|=(cur<las);//比较大小 
        las=cur;
        return;
    }
    //下面三行也可以好好体会一下跑的顺序 
    if(y==m) ok(x+1,y,n,m,cur);
    else if(x==n) ok(x,y+1,n,m,cur);
    else ok(x,y+1,n,m,cur),ok(x+1,y,n,m,cur);
    return;
}
inline int can(int x,int y,int v){a[x][y]=v;no_ans=0;las=0;ok(1,1,x,y,0);return !no_ans; }
inline int dfs(int x,int y,int n,int m){
    if(x==n+1) return ++ans;
    for(int i=0;i<=1;i++){
        if(can(x,y,i)){
            a[x][y]=i;
            //下面两行好好体会一下路径走的顺序 
            if(y==m) dfs(x+1,1,n,m);
            else dfs(x,y+1,n,m);
        }    
    }
    return 0;
}
inline int calc(int n,int m){ans=0;dfs(1,1,n,m);return ans;}
int main(){
    for(int n=2;n<=7;n++){
        printf("ans(%d, %d) = %d
",n,n,calc(n,n));
        printf("ans(%d, %d) = %d
",n,n+1,calc(n,n+1));
        printf("ans(%d, %d) = %d
",n,n+2,calc(n,n+2));
        printf("ans(%d, %d) = %d
",n,n+3,calc(n,n+3));
    }
    return 0;
}
View Code

然后就发现规律,

第一个很显然,n=1即第三个和n=2和n=3看数据范围就晓得可能有特殊性质,第二(n,m和n,m-1)、五(n+1,n+1和n,n)、六(n,n+1和n,n)个比较难看,基本上就是多猜特殊性质,多输出特殊的组(如n=1,2,3..或者n,n或者n,m和m-1/m+1,n,n和n+1,n+1等等)。

 于是打出AC代码:

#include<bits/stdc++.h>
#define ri register int
#define ll long long
#define For(i,l,r) for(ri i=l;i<=r;i++)
#define Dfor(i,r,l) for(ri i=r;i>=l;i--)
using namespace std;
ll f[10],n,m;
const int p=1e9+7;
inline ll read(){
    ll f=1,sum=0;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();}
    return f*sum;
}
inline ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=1ll*ans*a%p;
        a=1ll*a*a%p;
        b>>=1;
    }
    return ans;
}
int main(){
    n=read(),m=read();
    if(n>m) swap(n,m);
    if(n==1){
        printf("%lld
",ksm(2,m));
        return 0;
    }
    f[2]=12,f[3]=112,f[4]=912;
    For(i,4,n-1) f[i+1]=(8ll*f[i]%p-10ll*ksm(2,i)%p+p)%p;
    if(n==m){
        printf("%lld
",f[n]);
        return 0;    
    }
    ll g;
    if(n==2) g=36;
    else if(n==3) g=336;
    else g=(3ll*(f[n]-ksm(2,n))%p+p)%p;
    printf("%lld
",(ll)g*ksm(3,m-n-1)%p);
}
View Code

 

原文地址:https://www.cnblogs.com/jian-song/p/11837834.html