【第三篇blog】第一次模拟赛反思与解析

来源:互联网 发布:mac系统u盘制作 编辑:程序博客网 时间:2024/06/05 03:31

模拟赛题目选自USACO铜组

个人翻译,严禁转载

——————————————————————我是更新提示分割线———————————————————————

<第一次更新>使用完整题目,切勿转载。

—————————————————————我是华丽丽的正文分割线——————————————————————

T1

1.栅栏作画
【问题描述】
冬去秋来,时光总是会改变一些东西。随着农夫Farmer John的老去,他的栅栏也越来越丑陋了,本着处女座的原则,农夫Farmer John决定做点什么了!他要给他的栅栏重新作画。但是年老的Farmer John并不能独立完成所有的栅栏的绘画。所以他找到了他最钟爱的奶牛Bessie,来帮助他完成工作。
为了简化问题,我们把所有栅栏看成一条直线,每个栅栏杆是这个直线上的单位长度。John开始从a刻度到b刻度之间的栅栏进行绘画。也就是说他完成了b-a个栅栏的绘画(b>a),比如说a=3 b=5,那么John就完成了两个栅栏的绘画。
同时,奶牛Bessie完成c到d的绘画,但是年老的John无法回忆起他已经对那些栅栏进行处理了,所以对于c到d可能和a到b有重复的绘画处。那么我们要求求出一共对多少个栅栏进行了绘画.(c>d,a>b)

【输入】
输入数据一共有两行,第一行分别为a和b,第二行分别为c和d。均用一个空格隔开。

【输出】
输出一个正整数,表示总共对多少个栅栏进行了绘画。

【输入输出样例1】
paint.in paint.out
7 10
4 8 6

【数据范围】
保证所有数据在[0,100]区间且均为正整数。

题意:读题可知,即求数轴上有一定位置关系的两线段非重叠长度和。

解析:此类题目基本有两种方法,数学法和强模拟,由于数据量并不大,推荐强模拟。数学法容易涉及边界问题,模拟使用布尔数组进行标记即可。

思路:输入数据,两个for循环对fj和奶牛的数据分别在bool数组上标注为1(bool数组初始全0),for循环统计数组中1的个数,输出。

参考代码如下:

#include<bits/stdc++.h>using namespace std;int main(){    freopen("paint.in","r",stdin);    freopen("paint.out","w",stdout);    int f[1000];//标记的数组    memset(f,0,sizeof(f));//清空    int fa,fb,ba,bb;    cin>>fa>>fb>>ba>>bb;    for(int i=fa;i<=fb-1;i++)    {        f[i+1]=1//开始标记第一组数据    }    for(int i=ba;i<=bb-1;i++)    {        f[i+1]=1;//开始标记第二组数据    }    int sum=0;    for(int j=1;j<=1000;j++)    {        if(f[j]==1)sum++;//统计    }    cout<<sum<<endl;    return 0;   }

得分情况:一次AC

T2

失去的母牛

题目描述
FJ丢失了他引以为傲的牛Bessie,他必须找到他!
幸运的是,农场间只有一条长路径,而且FJ知道Bessie会在这条路的一些点上。如果我们把这条路看作一条数轴,那么FJ现在在x点上,而Bessie在y点上(FJ不确定)。如果FJ只知道Bessie大致在哪里,他只能径直向它走|x-y|的距离。不幸的是,由于黑山老树精的出没,外面很黑,FJ看不见任何东西。他唯一能找到Bessie的办法是来回走动直到他最终到达了Bessie所在的位置。
为了找出搜索的最佳方案,FJ咨询了信息大佬——Aico。Aico告诉他这是个经典的计算机问题,叫做“Lost Cow Problem”(丢失牛问题)(这是真的!)。
FJ找牛的最佳方案是先移动到x+1的位置,然后反向移动到x-2,接着是x+4,以此类推。在一个“之字形”模式中,他每一步移动后离起点的距离是上一步时离起点距离的两倍(x+1,x-2,x+4)。正如他在学习“丢失牛问题”算法时一样,这种方式能让他在最坏情况下总共走9倍的实际距离(|x-y|)。(这也是真的!9倍实际距离实际上就是这种算法最坏的情况)
Farmer John想去验证这个结果。已知x和y,请编程计算他找到Bessie所行走的距离。
输入输出格式
输入格式:(lostcow.in)
一行两个数据 x和y。
输出格式:(lostcow.out)
一个数据,表示Farmer John将前往Bessie的距离。
输入输出样例
输入样例:
3 6
输出样例:
9
数据范围
0<=x,y<=1000

题意:模拟题,即模拟fj来回走动(来回扫描),求所走路程。

解析:奶牛模拟题,读懂题意并进行模拟即可。

思路:输入数据,使用两个变量标记当前要走的路程,一个标记正负,一个标记距离,使用一个变量作当前位置模拟走动,每走动一步总步数增加,如果当前位置等于奶牛位置,跳出循环,输出当前步数。

参考代码如下:

#include<bits/stdc++.h>using namespace std;int main(){    freopen("lostcow.in","r",stdin);    freopen("lostcow.out","w",stdout);    int x,y;//x为初始位置,y为目标位置    cin>>x>>y;    int now=x,sum=0;//now为当前位置,sum为总步数    int f=0;//f为正负标记    double result=0.5;//result为变量标记    while(1)//未找到目标情况下无穷循环    {        result*=2;//往前往后位置的变量每一次乘2        if(f==0)f++;        else f--;//f变量每次改变控制正负        if(f==1)        {            for(;now<(x+result);)//模拟            {                now++;                sum++;                if(now==y)goto ready;//如果找到目标,跳出循环            }        }        else        {            for(;now>(x-result);)//模拟            {                now--;                sum++;                if(now==y)goto ready;//如果找到目标,跳出循环            }        }    }    ready://输出        cout<<sum<<endl;        return 0;   }

得分情况:一次AC

T3

牛的基因组学

题目描述
农夫fj拥有n头有斑点的奶牛和n头没有斑点的奶牛。由于她刚刚完成了关于牛的基因的一门课程,所以她相信,她的奶牛身上的斑点是由于奶牛基因组上单个位置的基因突变引起的。农夫fj花费了巨大的代价,把她的奶牛的基因组进行了排序。每一个基因组都是一个由ACGT四个字母组成的长度为m的字符串。当她排列她的牛的基因组时,她得到了以下的表格,(此时n=3)
位置 1 2 3 4 5 6 7 … M
有斑点的牛 1 A A T C C C A … T
有斑点的牛 2 G A T T G C A … A
有斑点的牛 3 G G T C G C A … A
无斑点的牛 1 A C T C C C A … G
无斑点的牛 2 A C T C G C A … T
无斑点的牛 3 A C T T C C A … T
仔细观察这张表,她推测,位置2是基因组中可能解释斑点的潜在位置。也就是说,通过查看这张表,农夫fj可以预测她的哪头奶牛是有斑点的,哪些不是(这里,A或G意味着斑点,C意味着无斑点; T是无关紧要的,因为它不会出现在任何奶牛的位置2)。位置1本身不足以解释斑点,因为这个位置的A可能表明一头斑点的牛或一头无斑点牛。
给出农民fj的奶牛的基因组,请计算潜在解释斑点的数目。
输入输出格式
输入格式(文件名 cownomics.in):
输入数据第一行包含两个小于100的正整数N和M。下一行至第N+1行每行包含一串长为M的字符串,表示斑点牛的基因组。第N+2行至最后每行同样包含一串长为M的字符串,表示普通奶牛的基因组。
输出格式(文件名 cownomics.out):
请计算在基因组中可能导致斑点病的位置的数量(一个大于等于0,小于等于M的整数)。
样例输入输出
样本输入
3 8
AATCCCAT
GATTGCAA
GGTCGCAA
ACTCCCAG
ACTCGCAT
ACTTCCAT
样本输出
1

题意:本题和现在流行的比赛题相似,具有较长的题面,翻译也较困难,不可能很精确。意为在有斑点和无斑点的牛的基因组中找的完全不同的基因组,即该组别位置没有两种牛共同拥有的基因,输出这样的组别有几组。

解析:分析可知题目数据量不大,三重循环扫描即可。

思路:输入,三重循环i,j,k,分别表示第i组基因,第i组基因中有斑点牛第j个位置的基因,无斑点牛第k个位置的基因,一旦位置i的斑点基因j的字母和非斑点基因k的字母相同,跳过i这个位置,否则答案数量增加,输出。

参考代码如下:

#include<bits/stdc++.h>using namespace std;int main(){    int n,m,f=0,sum=0;//n,m如题意,sum为符合要求的基因组的数量,f标记当前位置是否合法    cin>>n>>m;    char bd[1000][1000],wbd[1000][1000];//ban斑dian点,wu无ban斑dian点    for(int i=1;i<=n;i++)    {        cin>>bd[i];//输入    }    for(int i=1;i<=n;i++)    {        cin>>wbd[i];//输入    }    for(int i=0;i<=m-1;i++)//循环枚举    {        f=0;//初始标记当前位置i合法        for(int j=1;j<=n;j++)        {            for(int k=1;k<=n;k++)            {                if(bd[j][i]==wbd[k][i])f=1;//如果i个位置中的无斑点基因和有斑点基因相同,该位置不合法            }         }        if(f==0)sum++;//该位置合法,答案数量增加    }    cout<<sum<<endl;//输出    return 0;} 

得分情况:样例分
分析:考试时未读懂题意,缺乏做题经验,误以为样例中的字母就是判断是否合法的字母。

T4

现代艺术
题目描述:
世界各地的艺术评论家直到现在才开始意识到伟大的牛画家Bibi的创意天赋。
Bibi用一种特殊的方式绘画。她用一块N*N的画布开始画画 “0”表示一个画布的空单元格。然后她在画布上画了9个矩形。她会使用9种颜色的一种(为了方便(Bibi是个很懒的人),她把颜色编号为1~9). 她每次可以选择任意一种未使用过的颜色进行绘画。
举个例子,如果她从颜色2开始画,下面是她画画的过程:
2220
2220
2220
0000

然后她可能画了一个颜色为7的矩形:
2220
2777
2777
0000

随后她画了一个颜色为3的小矩形:
2230
2737
2777
0000

每一个矩形的边都是平行于边缘的,鉴于画布的最终状态,请计算出画布上有多少种颜色可能是第一次被画上去的。
(矩形的大小是不确定的 可能是一个单元格 也可能覆盖整个画布)
输入格式(文件名:art.in)

第一行是整数n(1<=n<=10)下面n*n的矩阵由数字0~9组成,描述的是最后完成的画布。

输出格式(文件名 art.out)

输出一个整数 表示最终画布的颜色中,可能为第一个画上去的颜色个数。

样例输入:
4
2230
2737
2777
0000

样例输出:
1

样例解释:在本例中,只有颜色2可能是第一个被绘制的。颜色3显然是在颜色7之后画的,而颜色7显然是在颜色2之后画的。

题意:找出画布中可能是第一个涂上颜色的颜色数量。

解析:本题为本组题的压轴题,具有一定难度。需要特殊算法扫描每种颜色的最大最小行列,再进行是否被其他颜色覆盖的判断。

思路:输入,循环i枚举每种颜色,四次循环找到该颜色的最大最小行列,再用两重循环扫描最大最小行列的方阵,如果扫到方阵中有不同与i的颜色,则对扫到的颜色进行标记,因为该颜色在其他颜色的方阵内,肯定是覆盖在其他颜色上的,所以该颜色就一定不是第一个涂上的颜色。最后一个循环扫描没被标记的颜色,输出。

标程代码如下:

#include<bits/stdc++.h>using namespace std;int n,vis[10]={}; //vis[i]>0表示不是我要求的颜色,颜色分两类,1)没出现过2)被其他颜色包含 char f[20][20];void init(){ scanf("%d",&n); scanf("%c",&f[1][1]); for(int i=1;i<=n;++i)  for(int j=1;j<=n+1;++j)   scanf("%c",&f[i][j]);     return;    }void chuli(){ int ans=0;  for(int i=1;i<=9;++i)     {   int x0=0,y0=0,x1=0,y1=0;   for(int y=1;y<=n;++y)     for(int x=1;x<=n;++x)     if(f[x][y]==i+48) {y1=y;break;}     //y1为颜色i的最小列    for(int y=n;y>=1;--y)    for(int x=1;x<=n;++x)     if(f[x][y]==i+48) {y0=y;break;}          //y0 为最 大列    for(int x=1;x<=n;++x)    for(int y=1;y<=n;++y)     if(f[x][y]==i+48) {x1=x;break;}       for(int x=n;x>=1;--x)    for(int y=1;y<=n;++y)     if(f[x][y]==i+48) {x0=x;break;}     //x1为  最小行,x0为最大行    if(x0==0&&y0==0&&x1==0&&y1==0) {vis[i]++;continue;}   for(int x=x0;x<=x1;++x)    for(int y=y0;y<=y1;++y)     if(f[x][y]!=i+48&&f[x][y]!=48)  //如果 f[x][y]和颜色i不相同,那么这个颜色必然不是第一次出现          vis[f[x][y]-48]++;//vis[i]表示编号为i的颜色不是第一次出现   }   for(int i=1;i<=9;++i)   if( vis[i]==0)     ans++;  printf("%d",ans);}int main(){ freopen("art.in","r",stdin); freopen("art.out","w",stdout); init(); chuli();    return 0;}

得分情况:0分
分析:考试时间不足,没有合理安排做题和排错时间。

总结

没有合理安排考试时间,需要在做题前通览所以题目,对题目难易程度进行排序,进而合理答题,深刻理解题意。
—————————————————————我是华丽丽的正文分割线——————————————————————

——————————————————————我是讲废话的分割线———————————————————————

原创粉丝点击