NOIP2014 Day1

T1水题:

P1328 生活大爆炸版石头剪刀布

#include<bits/stdc++.h>
using namespace std;
#define N 205
#define ri register int
int a[N],b[N];
int check(int a,int b)
{
    if(a==b) return 0;
    if(a==0){
        if(b==1 ||b==4) return 2;
        return 1;
    }
    if(a==1){
        if(b==2 || b==4) return 2;
        return 1;
    }
    if(a==2){
        if(b==0 || b==3) return 2;
        return 1;
    }
    if(a==3){
        if(b==0 || b==1) return 2;
        return 1;
    }
    if(a==4){
        if(b==3 || b==2) return 2;
        return 1;
    }
    return 0;
}
int main()
{
    int n,n1,n2;
    scanf("%d%d%d",&n,&n1,&n2);
    for(ri i=1;i<=n1;++i) scanf("%d",&a[i]);
    for(ri i=1;i<=n2;++i) scanf("%d",&b[i]);
    int i=1,j=1,A=0,B=0;
    while(n--){
        if(i>n1) i=1;
        if(j>n2) j=1;
        
        int x=check(a[i],b[j]);
        //printf("a:%d b:%d x:%d
",a[i],b[j],x);
        if(x==1) A++;
        else if(x==2) B++;
        i++,j++;
    }
    printf("%d %d
",A,B);
}
/*
10 5 6
0 1 2 3 4
0 3 4 2 1 0
*/
View Code

T2水题:

P1351 联合权值

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200005
#define mod 10007
#define ri register int
ll ans=0,maxx=0,lmx[N],mx[N],sum[N],w[N];
int tot=0,head[N],nex[N<<1],to[N<<1],fa[N];
void add(int a,int b) { to[++tot]=b; nex[tot]=head[a]; head[a]=tot; }
void dfs1(int u,int ff)
{
    for(ri i=head[u];i;i=nex[i]){
        int v=to[i];
        if(v==ff) continue;
        sum[u]+=w[v]; //sum[u]%=mod; 注意sum不要取mod 否则会在下面减成负数!!! 
        if(!mx[u]) mx[u]=w[v];
        else if(w[v]>mx[u]) lmx[u]=mx[u],mx[u]=w[v];
        else if(w[v]>lmx[u]) lmx[u]=w[v];
        fa[v]=u;
        dfs1(v,u);
    }
}
void dfs2(int u,int ff)
{
    for(ri i=head[u];i;i=nex[i]){
        int v=to[i];
        if(v==ff) continue;
        ans+=w[v]*(sum[u]-w[v]) %mod; ans%=mod;
        ans+=w[v]*w[ff] %mod *2 %mod; ans%=mod;
        maxx=max(maxx,w[v]*w[ff]);
        dfs2(v,u);
    }
    maxx=max(maxx,mx[u]*lmx[u]);
}
int main()
{
    int n,a,b;
    scanf("%d",&n);
    for(ri i=1;i<=n-1;++i) scanf("%d%d",&a,&b),add(a,b),add(b,a);
    for(ri i=1;i<=n;++i) scanf("%lld",&w[i]);
    dfs1(1,0);
    dfs2(1,0);
    printf("%lld %lld
",maxx,ans%mod);
}
/*
6
1 2
1 3
1 4
2 6
2 5
1 2 3 4 5 6
*/
View Code

T3简单dp:

P1941 飞扬的小鸟

分析:

对于简单的模拟水题,应该看清楚题目要求和数据范围。

对于有减法又有%的题,注意不要减成负数,要( ……+mod )%mod。

T3的直接dp,复杂度大,只能得75分:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x7f7f7f
#define N 10005
#define M 1005
#define ll long long
#define ri register int
int x[N],y[N];
ll dp[N][M];
struct node{
    int u,v,fl;
}g[N];
int main()
{
    int n,m,k,a,b,c,fll=0,tmp;
    scanf("%d%d%d",&n,&m,&k);
    for(ri i=0;i<=n-1;++i) scanf("%d%d",&x[i],&y[i]);
    for(ri i=1;i<=k;++i) scanf("%d%d%d",&a,&b,&c),g[a].u=b,g[a].v=c,g[a].fl=1;
    for(ri i=0;i<=n;++i)
    if(!g[i].fl) g[i].u=0,g[i].v=m+1;
    for(ri i=0;i<=n;++i) for(ri j=0;j<=m;++j) dp[i][j]=inf;
    for(int i=g[0].u;i<=g[0].v;++i) dp[0][i]=0;
    for(ri i=0;i<=n-1;++i){//
        bool fl=0;
        for(ri j=g[i].u+1; j<=g[i].v-1 ; ++j){
            int pos= j-y[i] ;//上一次不点 这一次的高度
            if( pos<g[i+1].v && pos>g[i+1].u ) //可以通过这一个管道 
            dp[i+1][pos]=min(dp[i+1][pos] , dp[i][j]);
            int up=( g[i+1].v-j )/x[i] +1, down= ( g[i+1].u-j )/x[i];//上一次最多点的次数和最少点的次数 
            down=max(1,down);
            for(ri k=down;k<=up;++k){
                pos=j+x[i]*k;//点k次后这一次的高度 
                if( pos>0 && (!g[i+1].fl) && pos>m ) pos=m;
                if( pos<g[i+1].v && pos>g[i+1].u ) 
                dp[i+1][pos]=min(dp[i+1][pos] , dp[i][j]+k);
            }
        }
        for(ri j=g[i+1].u+1; j<=g[i+1].v-1; ++j) if(dp[i+1][j]!=inf) fl=1;
        if(!fl) { fll=1; tmp=i; break; }
    }
    if(fll){//统计最多到的水管数 
        ll ans=0;
        for(ri i=1;i<=tmp;++i) 
        ans+=g[i].fl;
        printf("0
%lld
",ans);
        return 0;
    }
    ll ans=inf;
    for(ri i=g[n].u+1;i<=g[n].v-1;++i) ans=min(ans,dp[n][i]);
    printf("1
%lld
",ans);
    return 0;
}
/*
10 10 6 
3 9  
9 9  
1 2  
1 3  
1 2  
1 1  
2 1  
2 1  
1 6  
2 2  
1 2 7 
5 1 5 
6 3 5 
7 5 8 
8 7 9 
9 1 3 

*/
简单dp 75

正解是背包或者利用背包的思路进行优化:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x7f7f7f
#define N 10005
#define M 2005
#define ll long long
#define ri register int
int x[N],y[N];
ll dp[N][M];
struct node{
    int u,v,fl;
}g[N];
int main()
{
    int n,m,k,a,b,c,fll=0,tmp;
    scanf("%d%d%d",&n,&m,&k);
    for(ri i=1;i<=n;++i) scanf("%d%d",&x[i],&y[i]);
    for(ri i=1;i<=k;++i) scanf("%d%d%d",&a,&b,&c),g[a].u=b,g[a].v=c,g[a].fl=1;
    for(ri i=0;i<=n;++i)
    if(!g[i].fl) g[i].u=0,g[i].v=m+1;
    for(ri i=0;i<=n;++i) for(ri j=0;j<=m+1;++j) dp[i][j]=inf;
    for(int i=g[0].u+1;i<=g[0].v-1;++i) dp[0][i]=0;
    for(ri i=1;i<=n;++i){
        for(ri j=x[i]+1;j<=m+x[i];++j)//上升是完全背包 
        dp[i][j]=min( dp[i-1][j-x[i]]+1 , dp[i][j-x[i]]+1 );
        
        for(ri j=m+1;j<=m+x[i];++j)//处理超过m的部分 
        dp[i][m]=min(dp[i][m],dp[i][j]);
        
        for(ri j=1;j<=m-y[i];++j)//下降是01背包 
        dp[i][j]=min(dp[i][j],dp[i-1][j+y[i]]);
        
        for(ri j=0;j<=g[i].u;++j) dp[i][j]=inf;//将不能到达的地方赋成inf 
        for(ri j=g[i].v;j<=m;++j) dp[i][j]=inf;
    }
    ll ans=inf; int fl=0;
    for(ri i=1;i<=m;++i) ans=min(ans,dp[n][i]);
    if(ans==inf){
        int pos;
        for(ri i=n;i>=0;--i){//倒着回去看 是哪个横坐标飞不过去了 
            for(ri j=1;j<=m;++j)
            if(dp[i][j]<inf) { fl=1; break ; }
            if(fl) { pos=i; break; }
        }
        ans=0;
        for(ri i=0;i<=pos;++i) ans+=g[i].fl;//统计水管数 
        printf("0
%lld
",ans);
        return 0;
    }
    printf("1
%lld
",ans);
    return 0;
}
/*
10 10 6 
3 9  
9 9  
1 2  
1 3  
1 2  
1 1  
2 1  
2 1  
1 6  
2 2  
1 2 7 
5 1 5 
6 3 5 
7 5 8 
8 7 9 
9 1 3 

*/
View Code

总之,题虽简单,还是有很多细节要注意的。

原文地址:https://www.cnblogs.com/mowanying/p/11529132.html