zoukankan      html  css  js  c++  java
  • 7.3模拟比赛解题报告

    067.3  NOIP模拟赛

    说明:本次考试3道题3个小时。

    1、洛谷P1003 铺地毯==codevs1134 铺地毯

    题目描述

    为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有 n 张地毯,编号从 1 到n 。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。

    地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。

    输入输出格式

    输入格式:

    输入文件名为carpet.in 。

    输入共n+2 行。

    第一行,一个整数n ,表示总共有 n 张地毯。

    接下来的n 行中,第 i+1 行表示编号i 的地毯的信息,包含四个正整数 a ,b ,g ,k ,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标(a ,b )以及地毯在x轴和y 轴方向的长度。

    第n+2 行包含两个正整数 x 和y,表示所求的地面的点的坐标(x ,y)。

    输出格式:

    输出文件名为carpet.out 。

    输出共1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出-1 。

    输入输出样例

    输入样例#1:
    【输入样例1】
    3
    1 0 2 3
    0 2 3 3
    2 1 3 3
    2 2
    【输入样例2】
    3
    1 0 2 3
    0 2 3 3
    2 1 3 3
    4 5
    输出样例#1:
    【输出样例1】
    3
    【输出样例2】
    -1
    

    说明

    【样例解释1】

    如下图,1 号地毯用实线表示,2 号地毯用虚线表示,3 号用双实线表示,覆盖点(2,2)的最上面一张地毯是 3 号地毯。

    【数据范围】

    对于30% 的数据,有 n ≤2 ;

    对于50% 的数据,0 ≤a, b, g, k≤100;

    对于100%的数据,有 0 ≤n ≤10,000 ,0≤a, b, g, k ≤100,000。

    noip2011提高组day1第1题

    太水了,不解释

    AC代码:

    #include<iostream>
    using namespace std;
    #define N 100100
    int a[N],b[N],c[N],d[N],k=-1,n,x,y;
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)
            cin>>a[i]>>b[i]>>c[i]>>d[i];
        cin>>x>>y;
        for(int i=1;i<=n;i++)
            if(x-a[i]>=0&&x-a[i]<=c[i]&&y-b[i]>=0&&y-b[i]<=d[i])
                k=i;
        cout<<k<<endl;
        return 0;
    }

     

    2、洛谷P1079 Vigenère 密码==codevs1197 Vigenère密码

    题目描述

    16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密

    码。Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为

    南军所广泛使用。

    在密码学中,我们称需要加密的信息为明文,用 M 表示;称加密后的信息为密文,用

    C 表示;而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,

    记为 k。 在 Vigenère 密码中,密钥 k 是一个字母串,k=k1k2…kn。当明文 M=m1m2…mn时,

    得到的密文 C=c1c2…cn,其中 ci=mi®ki,运算®的规则如下表所示:

    Vigenère 加密在操作时需要注意:

    1. ®运算忽略参与运算的字母的大小写,并保持字母在明文 M 中的大小写形式;

    2. 当明文 M 的长度大于密钥 k 的长度时,将密钥 k 重复使用。

    例如,明文 M=Helloworld,密钥 k=abc 时,密文 C=Hfnlpyosnd。

    输入输出格式

    输入格式:

    输入共 2 行。

    第一行为一个字符串,表示密钥 k,长度不超过 100,其中仅包含大小写字母。第二行

    为一个字符串,表示经加密后的密文,长度不超过 1000,其中仅包含大小写字母。

    输出格式:

    输出共 1 行,一个字符串,表示输入密钥和密文所对应的明文。

    输入输出样例

    输入样例#1:
    CompleteVictory
    Yvqgpxaimmklongnzfwpvxmniytm 
    输出样例#1:
    Wherethereisawillthereisaway 

    说明

    【数据说明】

    对于 100%的数据,输入的密钥的长度不超过 100,输入的密文的长度不超过 1000,且

    都仅包含英文字母。

    NOIP 2012 提高组 第一天 第一题

    注意点这里,其余问题不大

    AC代码:

    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define N 1024
    char key[N],a[N];
    inline int dx(char c){//锁定原字母的大小写 
        if(c>='A'&&c<='Z')return 1;
        else if(c>='a'&&c<='z')return 0;
    }
    inline char deal(char c,int i){//处理之后密文的大小写 
        if(i==1&&c>='a'&&c<='z')return c-32;
        else if(i==0&&c>='A'&&c<='Z')return c+32;
        else return c;
    }
    void action(){
        int lena=strlen(a),lenk=strlen(key);
        char c1,c2,ans;
        for(int i=0;i<lena;i++){
            int flag=dx(a[i]);
            c1=deal(a[i],1);
            c2=deal(key[i%lenk],1);//密钥可能短 
            int xx=c1-'A'-(c2-'A');
            if(xx<0) xx+=26;//翻译 
            ans=deal(xx+'A',flag);
            printf("%c",ans);
        }
        puts("");
    }
    int main(){
        scanf("%s%s",key,a);
        action();
        return 0;
    }

    3、洛谷P1514 引水入城==codevs1066 引水入城

    题目描述

    在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。

    为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。

    因此,只有与湖泊毗邻的第1 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。由于第N 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。

    输入输出格式

    输入格式:

    输入文件的每行中两个数之间用一个空格隔开。输入的第一行是两个正整数N 和M,表示矩形的规模。接下来N 行,每行M 个正整数,依次代表每座城市的海拔高度。

    输出格式:

    输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有几座干旱区中的城市不可能建有水利设施。

    输入输出样例

    输入样例#1:
    【输入样例1】
    2 5
    9 1 5 4 3
    8 7 6 1 2
    
    【输入样例2】
    3 6
    8 4 5 6 4 4
    7 3 4 3 3 3
    3 2 2 1 1 2
    输出样例#1:
    【输出样例1】
    1
    1
    
    【输出样例2】
    1
    3

    说明

    【样例1 说明】

    只需要在海拔为9 的那座城市中建造蓄水厂,即可满足要求。

    【样例2 说明】

    上图中,在3 个粗线框出的城市中建造蓄水厂,可以满足要求。以这3 个蓄水厂为源头

    在干旱区中建造的输水站分别用3 种颜色标出。当然,建造方法可能不唯一。

    【数据范围】

    这个题有意思,着重讲一下。

    闲扯一会儿:

    考试的时候思路基本上和题解一样,就连dp方程都一样~~貌似以前看过。

    考试的时候,想着bfs比dfs快,结果是bfs->TLE,dfs->AC.那分啊,心疼死我了,tyts。

    考试代码:

     

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define N 1010
    int dx[]={1,0,-1,0};
    int dy[]={0,1,0,-1};
    int bo[N],vis[N],l[N],r[N],f[N];
    struct node{
        int x,y,v;
    }map[N][N];
    int n,m;
    int bfs(int s,int x,int y){
        queue<node>que;
        que.push(map[x][y]);
        while(!que.empty()){
            node h=que.front();que.pop();
            for(int i=0;i<4;i++){
                int xx=h.x+dx[i],yy=h.y+dy[i];
                if(h.v>map[xx][yy].v&&xx>0&&xx<=n&&yy>0&&yy<=m){
                    que.push(map[xx][yy]);
                    if(xx==n&&!vis[yy]){
                        vis[yy]=1,bo[yy]++;
                        if(yy<l[s]||!l[s]) l[s]=yy;
                        if(yy>r[s]) r[s]=yy;
                    }  
                }
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&map[i][j].v);
                map[i][j].x=i;map[i][j].y=j;
            }
        }
        int sum=0,flag=0;
        for(int i=1;i<=m;i++){
            if(i>1&&map[1][i].v<map[1][i-1].v) continue;
            if(i<m&&map[1][i].v<map[1][i+1].v) continue;
            memset(vis,0,sizeof(vis));
            bfs(i,1,i);
        }
        for(int i=1;i<=m;i++){
            if(!bo[i]){
                flag=1;sum++;
            }
        }
        if(flag){printf("0
    %d
    ",sum);return 0;}
        printf("1
    ");
        for(int i=1;i<=m;i++){
            for(int j=l[i];j<=r[i];j++){
                if(f[j]>f[l[i]-1]+1||!f[j])
                    f[j]=f[l[i]-1]+1;
            }
        }
        printf("%d
    ",f[m]);
        return 0;
    }

    我看了各种题解,都说每个点(i,j)只能搜一遍(为什么只能搜一遍???),改完之后,依然WA,bfs搜不到?

    解答:每次for 1->m都会有清零,so 每个点(i,j)会被搜多次,so以上纯属扯淡。就这样。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define N 510
    int dx[]={1,0,-1,0};
    int dy[]={0,1,0,-1};
    int bo[N],vis[N][N],l[N],r[N],f[N];
    struct node{
        int x,y,v;
    }map[N][N];
    int n,m;
    int bfs(int s,int x,int y){
        queue<node>que;
        que.push(map[x][y]);
        while(!que.empty()){
            node h=que.front();que.pop();
            for(int i=0;i<4;i++){
                int xx=h.x+dx[i],yy=h.y+dy[i];
                if(!vis[xx][yy]&&h.v>map[xx][yy].v&&xx>0&&xx<=n&&yy>0&&yy<=m){
                    vis[xx][yy]=1;
                    que.push(map[xx][yy]);
                    if(xx==n){
                        bo[yy]++;
                        if(yy<l[s]||!l[s]) l[s]=yy;
                        if(yy>r[s]) r[s]=yy;
                    }  
                }
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&map[i][j].v);
                map[i][j].x=i;map[i][j].y=j;
            }
        }
        int sum=0,flag=0;
        for(int i=1;i<=m;i++){
            if(i>1&&map[1][i].v<map[1][i-1].v) continue;
            if(i<m&&map[1][i].v<map[1][i+1].v) continue;
            memset(vis,0,sizeof(vis));
            bfs(i,1,i);
        }
        for(int i=1;i<=m;i++){
            if(!bo[i]){
                flag=1;sum++;
            }
        }
        if(flag){printf("0
    %d
    ",sum);return 0;}
        printf("1
    ");
        for(int i=1;i<=m;i++){
            for(int j=l[i];j<=r[i];j++){
                if(f[j]>f[l[i]-1]+1||!f[j])
                    f[j]=f[l[i]-1]+1;
            }
        }
        printf("%d
    ",f[m]);
        return 0;
    }

    解题思路:

    对于第一行的每个城市,我们可以预处理出在这座城市建立蓄水厂,水流能到达最下面一行的哪些城市;如果最终的题目是有解的,那么最后一行这些被覆盖的城市是连续的,反证:如果水流到达最下面一行的城市是断开不连续的,则说明中间有城市海拔比四周都高,其他城市过来的水流也流不上去,因此永远无法被覆盖,与我们之前的条件相矛盾。

    预处理出来每做城市的覆盖范围后,这道题就变成这样:给你长度为m的x轴,现在有m条线段,求覆盖x轴至少要多少根线段。

    我们既可以用DP,也可以用贪心,这里采用DP

    设,f[i]表示覆盖1~i所需要的最少线段g[j]表示线段i覆盖的区间

    则 dp方程:f(i) = min{ f[i] , f[g[j].L - 1] + 1 |  i >= g[i].L&&i <= g[i].R }

    AC代码(以下均为AC代码):

    性能与问题,望大家铭记于心。

    dfs便捷版

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define N 1010
    int dx[]={1,0,-1,0};
    int dy[]={0,1,0,-1};
    int bo[N],vis[N][N],map[N][N],l[N],r[N],f[N];
    int n,m;
    void dfs(int s,int x,int y){
        if(x==n){
            bo[y]=1;
            if(y<l[s]||!l[s]) l[s]=y;
            if(y>r[s]) r[s]=y;
        }
        int h=map[x][y];
        vis[x][y]=1;
        if(x<n&&map[x+1][y]<h&&!vis[x+1][y]) dfs(s,x+1,y);
        if(x>1&&map[x-1][y]<h&&!vis[x-1][y]) dfs(s,x-1,y);
        if(y<m&&map[x][y+1]<h&&!vis[x][y+1]) dfs(s,x,y+1);
        if(y>1&&map[x][y-1]<h&&!vis[x][y-1]) dfs(s,x,y-1);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&map[i][j]);
            }
        }
        int sum=0,flag=0;
        for(int i=1;i<=m;i++){
            if(i>1&&map[1][i]<map[1][i-1]) continue;
            if(i<m&&map[1][i]<map[1][i+1]) continue;
            memset(vis,0,sizeof(vis));
            dfs(i,1,i);
        }
        for(int i=1;i<=m;i++){
            if(!bo[i]){
                flag=1;sum++;
            }
        }
        if(flag){printf("0
    %d
    ",sum);return 0;}
        printf("1
    ");
        for(int i=1;i<=m;i++){
            for(int j=l[i];j<=r[i];j++){
                if(f[j]>f[l[i]-1]+1||!f[j])
                    f[j]=f[l[i]-1]+1;
            }
        }
        printf("%d
    ",f[m]);
        return 0;
    }

     bfs麻烦版

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define N 510
    int dx[]={1,0,-1,0};
    int dy[]={0,1,0,-1};
    int bo[N],vis[N][N],l[N],r[N],f[N];
    struct node{
        int x,y,v;
    }map[N][N];
    int n,m;
    int bfs(int s,int x,int y){
        queue<node>que;
        que.push(map[x][y]);
        while(!que.empty()){
            node h=que.front();que.pop();
            for(int i=0;i<4;i++){
                int xx=h.x+dx[i],yy=h.y+dy[i];
                if(!vis[xx][yy]&&h.v>map[xx][yy].v&&xx>0&&xx<=n&&yy>0&&yy<=m){
                    vis[xx][yy]=1;
                    que.push(map[xx][yy]);
                    if(xx==n){
                        bo[yy]++;
                        if(yy<l[s]||!l[s]) l[s]=yy;
                        if(yy>r[s]) r[s]=yy;
                    }  
                }
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&map[i][j].v);
                map[i][j].x=i;map[i][j].y=j;
            }
        }
        int sum=0,flag=0;
        for(int i=1;i<=m;i++){
            if(i>1&&map[1][i].v<map[1][i-1].v) continue;
            if(i<m&&map[1][i].v<map[1][i+1].v) continue;
            memset(vis,0,sizeof(vis));
            bfs(i,1,i);
        }
        for(int i=1;i<=m;i++){
            if(!bo[i]){
                flag=1;sum++;
            }
        }
        if(flag){printf("%d
    %d
    ",n==1?1:0,sum);return 0;}//这里还需要特判n=1时,可能是bfs的缺陷 
        printf("1
    ");
        for(int i=1;i<=m;i++){
            for(int j=l[i];j<=r[i];j++){
                if(f[j]>f[l[i]-1]+1||!f[j])
                    f[j]=f[l[i]-1]+1;
            }
        }
        printf("%d
    ",f[m]);
        return 0;
    }

    我以为是STL的问题,于是又手动敲了一遍。还是需要特判,bfs……哎……

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define N 510
    int ax[]={1,0,-1,0};
    int ay[]={0,1,0,-1};
    int dx[N*200],dy[N*200];//注意范围 
    int bo[N],vis[N][N],l[N],r[N],f[N];
    int map[N][N];
    int n,m;
    void bfs(int s,int rx,int ry){
        int head=-1,tail=0,f=0;
        dx[0]=rx;
        dy[0]=ry;
        while(head<tail){
            head++;
            int x0=dx[head],y0=dy[head];
            for(int i=0;i<4;i++){
                int x1=x0+ax[i],y1=y0+ay[i];
                if(!vis[x1][y1]&&map[x0][y0]>map[x1][y1]&&x1>0&&x1<=n&&y1>0&&y1<=m)    {
                    vis[x1][y1]=1;
                    dx[++tail]=x1;dy[tail]=y1;
                    if(x1==n){
                        bo[y1]++;
                        if(y1<l[s]||!l[s]) l[s]=y1;
                        if(y1>r[s]) r[s]=y1;
                    }  
                }
            }
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&map[i][j]);
            }
        }
        int sum=0,flag=0;
        for(int i=1;i<=m;i++){
            if(i>1&&map[1][i]<map[1][i-1]) continue;
            if(i<m&&map[1][i]<map[1][i+1]) continue;
            memset(vis,0,sizeof(vis));
            bfs(i,1,i);
        }
        for(int i=1;i<=m;i++){
            if(!bo[i]){
                flag=1;sum++;
            }
        }
        if(flag){printf("%d
    %d
    ",n==1?1:0,sum);return 0;}//这里还需要特判n=1时,可能是bfs的缺陷 
        printf("1
    ");
        for(int i=1;i<=m;i++){
            for(int j=l[i];j<=r[i];j++){
                if(f[j]>f[l[i]-1]+1||!f[j])
                    f[j]=f[l[i]-1]+1;
            }
        }
        printf("%d
    ",f[m]);
        return 0;
    }

     -----------------------------------------------------------------------------------------------------------------------------------------------

    华丽的分割线

    ------------------------------------------------------------------------------------------------------------------------------------------------

    反思:1、标志位设错,就会TLE,(考试代码为什么写一维的vis[],白白少了20分);

              2、简单搜索时,建议用dfs(至少不用特判(坑爹的出题人,~~~~(>_<)~~~~));

  • 相关阅读:
    源代码搭建应用(一)——动手搭建自己的计算集群系统
    [转载]Ubuntu 14.04中root 密码忘记解决方法
    如何用路由器改成WiFi Pineapple系统镜像网络流量
    DELPHI黑客编程(一):正向后门原理实现
    OpenWrt 路由器过滤广告的N种方法
    Windows 10 上强制Visual Studio以管理员身份运行
    DB2修改表字段
    Git Fast-forward提交
    C#(去、过滤)掉字符中的换行符
    VS读取文件或写入文件时出现中文乱码问题
  • 原文地址:https://www.cnblogs.com/shenben/p/5638010.html
Copyright © 2011-2022 走看看