zoukankan      html  css  js  c++  java
  • Noip2010提高组总结

      将Noip2010重新做了一遍,第一遍做下来居然只有290分,比当年浙江的一等线低了20分,因为各种坏习惯丢掉了许多分数,Noip时需要特别注意!

    T1:机器翻译

      第一题直接暴力,内存足够所以不用循环队列,5分钟AC:

    #include <cstdio>
    int stack[10000],now;
    int main(){
        int m,n;
        scanf("%d%d",&m,&n); int head=m;
        for(int i=0;i<m;i++)stack[i]=-1;
        for(int i=0;i<n;i++){
            bool flag=true;
            scanf("%d",&now);
            for(int j=head-m;j<head;j++)if(stack[j]==now){flag=false;break;}
            if(flag)stack[head++]=now;
        }
        printf("%d
    ",head-m);
        return 0;
    }
    

    T2:乌龟棋

      对于这道题目直接以四种卡片为状态进行四维Dp就可以了,注意DP时加上的是格子1*i+2*j+3*k+4*l的数值,而不是i+j+k+l的,一开始出错调试时都过不了,修改好AC:

    #include <cstdio>
    int t[5],a[40000],s[5];
    int f[41][41][41][41];
    int main(){
        int m,n,in,ans=0;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)scanf("%d",&a[i]);
        for(int i=0;i<m;i++)scanf("%d",&in),s[in]++;
        f[0][0][0][0]=a[0];
        for(int i=0;i<=s[1];i++)
        for(int j=0;j<=s[2];j++)
        for(int k=0;k<=s[3];k++)
        for(int l=0;l<=s[4];l++){
            if(f[i+1][j][k][l]<f[i][j][k][l]+a[1*i+2*j+3*k+4*l+1])
            f[i+1][j][k][l]=f[i][j][k][l]+a[1*i+2*j+3*k+4*l+1];
            if(f[i][j+1][k][l]<f[i][j][k][l]+a[1*i+2*j+3*k+4*l+2])
            f[i][j+1][k][l]=f[i][j][k][l]+a[1*i+2*j+3*k+4*l+2];
            if(f[i][j][k+1][l]<f[i][j][k][l]+a[1*i+2*j+3*k+4*l+3])
            f[i][j][k+1][l]=f[i][j][k][l]+a[1*i+2*j+3*k+4*l+3];
            if(f[i][j][k][l+1]<f[i][j][k][l]+a[1*i+2*j+3*k+4*l+4])
            f[i][j][k][l+1]=f[i][j][k][l]+a[1*i+2*j+3*k+4*l+4];
        }
        for(int i=0;i<=s[1];i++)
        for(int j=0;j<=s[2];j++)
        for(int k=0;k<=s[3];k++)
        for(int l=0;l<=s[4];l++){
            if(f[i][j][k][l]>ans&&(i+2*j+3*k+4*l+1==n))ans=f[i][j][k][l];
        }
        printf("%d
    ",ans);
        return 0;
    }
    

    T3:关押罪犯

      属于最大值最小问题,可以用二分答案,BFS检验一下,但是我直接用的是并查集,感觉就是先排序,然后按边权由大到小进行并查集,关在同一个地方的建1边,关在不同地方的建0边,当然,对于数据全都建1边,在传递时01交替即可,一开始因为懒,没有码余数体系,直接敲了异或,没考虑全面,只拿了六十分,后来还是老老实实地写了下余数体系,AC~

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int f[20005],r[20005];
    struct seg{
        int a,b,l;
        friend bool operator <(const seg&a,const seg&b){return a.l>b.l;} 
    }s[100005];
    int sf(int x){
        if (f[x]==x) return x;
        int fx=sf(f[x]);
        r[x]=(r[x]+r[f[x]])%2;
        return f[x]=fx;
    }
    void Union(int x,int y,int fx,int fy,int d)
    {
        f[fy]=fx;
        r[fy]=(2-r[y]+d+r[x])%2;
    }
    int main(){
        int m,n;
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].l);
        sort(s,s+m);
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=0;i<m;i++){
            int fa=sf(s[i].a),fb=sf(s[i].b);
            if(fa==fb){
                if(r[s[i].a]==r[s[i].b]){
                    printf("%d",s[i].l);
                    return 0;
                }
            }
            else Union(s[i].a,s[i].b,fa,fb,1);
        }
        puts("0");
        return 0;
    }
    

    T4:引水入城

      最后一题题目还是不错的,可惜推出了大半的结论,却因为代码的原因只拿了30分,特别反省一下,首先看到题目,想到floodfill,对于第一排的每一个点可以进行一次种子填充法,然后就可以知道能够填到的地方,但是这样子复杂度过高,那么是不是所有的点都要填一遍呢?

                                       

      观察上面这张图,我们可以发现,如果第一排要填充的点比周围的点低,那么在填充那个点的时候就可以直接填到这个点,即一定比填充此点要优,所以在填充时,只需要填比两边点都要大或相等的点,即上图中的8,6,4,那么填充之后得到的数据该怎么处理呢?

      对于每次填充其实都生成了一条线段,注意线段计算时只取第一段连续的可灌溉点,如果是不连续的,必然无解,因为水断点如果可以被另一条线段覆盖,则一定比当前优,因为其必然可以灌溉到当前线段所能灌到的所有点。

      最后是求最少线段覆盖的典型贪心问题了,一开始我以为O(n)可以解决,结果发现是错的,每次取有交集的最长线段必须要扫一遍才可以,否则不一定是最优的,贴上错误代码,警示一下!

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int map[505][505],m,n;
    int b[505][505];
    struct seg{int a,b;}s[505];
    bool cmp(seg x,seg y){
        if(x.a==y.a)return x.b>y.b;
        return x.a<y.a;
    }
    void floodfill(int x,int y){
        b[x][y]=1;
        if(x+1<=n&&map[x+1][y]<map[x][y]&&!b[x+1][y])floodfill(x+1,y); 
        if(x-1>0&&map[x-1][y]<map[x][y]&&!b[x-1][y])floodfill(x-1,y);
        if(y+1<=m&&map[x][y+1]<map[x][y]&&!b[x][y+1])floodfill(x,y+1);
        if(y-1>0&&map[x][y-1]<map[x][y]&&!b[x][y-1])floodfill(x,y-1);
    }
    int main(){
        freopen("flow.in","r",stdin);
        freopen("flow.out","w",stdout);
        int i,j,top=0;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&map[i][j]);
        for(i=1;i<=m;i++)if(map[1][i]>=map[1][i+1]&&map[1][i]>=map[1][i-1]){
            memset(b,0,sizeof b);
            floodfill(1,i);
            for(j=1;j<=m;j++)if(b[n][j]){s[top].a=j;break;}
            if(s[top].a==0)continue;
            for(j=s[top].a;;j++)if(!b[n][j]){s[top++].b=j-1;break;}
        }
        sort(s,s+top,cmp);
        int l=s[0].a,r=s[0].b,tmp=1;
        for(j=1;j<top;j++)if((s[j].a-1)<=r&&s[j].b>r){r=s[j].b;tmp++;}
        if(r==m&&l==1){puts("1");printf("%d
    ",tmp);}
        else{int tmp=0; 
            for(i=1;i<=m;i++)
            if(map[1][i]>=map[1][i+1]&&map[1][i]>=map[1][i-1])floodfill(1,i);
            for(j=1;j<=m;j++)if(!b[n][j])tmp++;
            puts("0");printf("%d
    ",tmp); 
        }
        return 0;
        fclose(stdin);fclose(stdout); 
    }
    

     然后是AC程序

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    int map[505][505],m,n;
    int b[505][505];
    struct seg{int a,b;}s[505];
    bool cmp(seg x,seg y){
        if(x.a==y.a)return x.b>y.b;
        return x.a<y.a;
    }
    void floodfill(int x,int y){
        b[x][y]=1;
        if(x+1<=n&&map[x+1][y]<map[x][y]&&!b[x+1][y])floodfill(x+1,y); 
        if(x-1>0&&map[x-1][y]<map[x][y]&&!b[x-1][y])floodfill(x-1,y);
        if(y+1<=m&&map[x][y+1]<map[x][y]&&!b[x][y+1])floodfill(x,y+1);
        if(y-1>0&&map[x][y-1]<map[x][y]&&!b[x][y-1])floodfill(x,y-1);
    }
    int main(){
        int i,j,top=0;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;i++)for(j=1;j<=m;j++)scanf("%d",&map[i][j]);
        for(i=1;i<=m;i++)if(map[1][i]>=map[1][i+1]&&map[1][i]>=map[1][i-1]){
            memset(b,0,sizeof b);
            floodfill(1,i);
            for(j=1;j<=m;j++)if(b[n][j]){s[top].a=j;break;}
            if(s[top].a==0)continue;
            for(j=s[top].a;;j++)if(!b[n][j]){s[top++].b=j-1;break;}
        }
        sort(s,s+top,cmp);
        int l=1,r=0,tmp=0; bool flag;
        do{
            int max=0; flag=1; 
            for(int i=0;i<top;i++)
            if(s[i].a-1<=r&&s[i].b>r){if(s[i].b>max)max=s[i].b;flag=0;}
            r=max; tmp++;
        }while(r!=m&&!flag);
        if(r==m){puts("1");printf("%d
    ",tmp);}
        else{int tmp=0; 
            for(i=1;i<=m;i++)
            if(map[1][i]>=map[1][i+1]&&map[1][i]>=map[1][i-1])floodfill(1,i);
            for(j=1;j<=m;j++)if(!b[n][j])tmp++;
            puts("0");printf("%d
    ",tmp); 
        }
        return 0;
    }
    

     注意点:

      1.不要忘记return 0;

      2.提交时while(1)记得要去掉!!!

      3.注意Noip时一定要开cstring,iostream不可以代替cstring!

      4.注意判断用双等号! 白丢70分的教训啊~

      5.加权并查集不可以用异或,100降为60分得出的结论

      6.一定要多造数据来检测自己的程序!

  • 相关阅读:
    cocos2d-x simpleGame 0
    cocos2d-x 下的HelloWorld
    cocos2d-x windows 配置
    算术入门之加减乘除
    计算摄氏温度
    输出倒三角图案
    厘米换算英尺英寸
    多文件模块的学生信息库系统
    GPS数据处理
    单词长度
  • 原文地址:https://www.cnblogs.com/forever97/p/Noip2010.html
Copyright © 2011-2022 走看看