模拟与高精度
1.乒乓球(模拟)
题目描述
华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在1111分制和2121分制下,双方的比赛结果(截至记录末尾)。
比如现在有这么一份记录,(其中W表示华华获得一分,L表示华华对手获得一分):
WWWWWWWWWWWWWWWWWWWWWWLW
在1111分制下,此时比赛的结果是华华第一局1111比00获胜,第二局1111比00获胜,正在进行第三局,当前比分11比11。而在2121分制下,此时比赛结果是华华第一局2121比00获胜,正在进行第二局,比分22比11。如果一局比赛刚开始,则此时比分为00比00。直到分差大于或者等于22,才一局结束。
你的程序就是要对于一系列比赛信息的输入(WLWL形式),输出正确的结果。
输入格式
每个输入文件包含若干行字符串,字符串有大写的WW、LL和EE组成。其中EE表示比赛信息结束,程序应该忽略E之后的所有内容。
输出格式
输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。其中第一部分是1111分制下的结果,第二部分是2121分制下的结果,两部分之间由一个空行分隔。
输入输出样例
输入 #1复制
WWWWWWWWWWWWWWWWWWWW
WWLWE
输出 #1复制
11:0
11:0
1:1
21:0
2:1
说明/提示
每行至多25个字母,最多有2500行
【题目来源】
NOIP 2003 普及组第一题
分析:
将若干行字符串均读入,储存在一个数组中,根据21分制或者11分制进行分组处理,输出结果,注意E后的数据不需要做处理,程序中应该对此有判断。
代码:
在oj里只给了80分,还有两个样例没过,不知道问题出在哪里,望大神指点。
#include<stdio.h>
#include<string.h>
#include<math.h>
int main()
{
char all[70000];
char each[30];
int len;
int i,j;
int count=0;//记录总数组的长度
while(scanf("%s",each)!=EOF)
{
len=strlen(each);
//printf("len=%d count=%d\n",len,count);
for(i=0;i<len;i++)
{
all[count+i]=each[i];
}
count+=len;
//puts(each);
//puts(all);
}
//11分制处理
//printf("count=%d\n",count);
int m,n;
m=n=0;
for(i=0;i<count;i++)
{
if(all[i]=='E')
break;
if(m>=11||n>=11)
{
if(abs(m-n)>=2)
{
printf("%d:%d\n",m,n);
m=n=0;
}
}
if(all[i]=='W') m++;
if(all[i]=='L') n++;
}
if(!(m==0&&n==0))//不全为0
printf("%d:%d\n\n",m,n);
m=n=0;
//21分制处理
for(i=0;i<count;i++)
{
if(all[i]=='E')
break;
if(m>=21||n>=21)
{
if(abs(m-n)>=2)
{
printf("%d:%d\n",m,n);
m=n=0;
}
}
if(all[i]=='W') m++;
if(all[i]=='L') n++;
}
if(!(m==0&&n==0))//不全为0
printf("%d:%d\n",m,n);
return 0;
}
补充:当时忘记考虑直接输入E应该输出0:0的情况,而是直接退出了,也忽略的当一局比赛刚刚结束,意味着一句比赛才刚刚开始也应该输出0:0.
修改后的代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
int main()
{
char all[70000];
char each[30];
int len;
int flag=1;
int i,j;
int isprime=0;
int count=0;//记录总数组的长度
while(scanf("%s",each)!=EOF)
{
len=strlen(each);
//printf("len=%d count=%d\n",len,count);
for(i=0;i<len;i++)
{
all[count+i]=each[i];
}
count+=len;
if(all[0]=='E')
{
isprime=1;
break;
}
}
//11分制处理
int m,n;
m=n=0;
for(i=0;i<count;i++)
{
if(all[i]=='E')
break;
flag=0;
if(all[i]=='W') m++;
if(all[i]=='L') n++;
//printf("m=%d n=%d\n",m,n);
if(m>=11||n>=11)
{
flag=1;
if(abs(m-n)>=2)
{
printf("%d:%d\n",m,n);
m=n=0;
}
}
//printf("flag=%d\n",flag);
}
//printf("flag=%d\n",flag);
if(flag==1||!(m==0&&n==0)||isprime==1)
printf("%d:%d\n",m,n);
printf("\n");
m=n=0;
//21分制处理
for(i=0;i<count;i++)
{
if(all[i]=='E')
break;
flag=0;
if(all[i]=='W') m++;
if(all[i]=='L') n++;
if(m>=21||n>=21)
{
flag=1;
if(abs(m-n)>=2)
{
printf("%d:%d\n",m,n);
m=n=0;
}
}
}
if(flag==1||!(m==0&&n==0)||isprime==1)
printf("%d:%d\n",m,n);
return 0;
}
2.玩具谜题(模拟)
题目描述
小南有一套可爱的玩具小人, 它们各有不同的职业。
有一天, 这些玩具小人把小南的眼镜藏了起来。 小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外。如下图:
这时singersinger告诉小南一个谜題: “眼镜藏在我左数第3个玩具小人的右数第11个玩具小人的左数第22个玩具小人那里。 ”
小南发现, 这个谜题中玩具小人的朝向非常关键, 因为朝内和朝外的玩具小人的左右方向是相反的: 面朝圈内的玩具小人, 它的左边是顺时针方向, 右边是逆时针方向; 而面向圈外的玩具小人, 它的左边是逆时针方向, 右边是顺时针方向。
小南一边艰难地辨认着玩具小人, 一边数着:
singersinger朝内, 左数第33个是archerarcher。
archerarcher朝外,右数第11个是thinkerthinker。
thinkerthinker朝外, 左数第22个是writewriter。
所以眼镜藏在writerwriter这里!
虽然成功找回了眼镜, 但小南并没有放心。 如果下次有更多的玩具小人藏他的眼镜, 或是谜題的长度更长, 他可能就无法找到眼镜了 。 所以小南希望你写程序帮他解决类似的谜題。 这样的谜題具体可以描述为:
有 nn个玩具小人围成一圈, 已知它们的职业和朝向。现在第11个玩具小人告诉小南一个包含mm条指令的谜題, 其中第 zz条指令形如“左数/右数第ss,个玩具小人”。 你需要输出依次数完这些指令后,到达的玩具小人的职业。
输入格式
输入的第一行包含两个正整数 n,mn,m,表示玩具小人的个数和指令的条数。
接下来 nn 行,每行包含一个整数和一个字符串,以逆时针为顺序给出每个玩具小人的朝向和职业。其中 00 表示朝向圈内,11 表示朝向圈外。 保证不会出现其他的数。字符串长度不超过 1010 且仅由小写字母构成,字符串不为空,并且字符串两两不同。整数和字符串之间用一个空格隔开。
接下来 mm 行,其中第 ii 行包含两个整数 a_i,s_ia
i
,s
i
,表示第 ii 条指令。若 a_i=0a
i
=0,表示向左数 s_is
i
个人;若 a_i=1a
i
=1,表示向右数 s_is
i
个人。 保证 a_ia
i
不会出现其他的数,1 \le s_i < n1≤s
i
<n。
输出格式
输出一个字符串,表示从第一个读入的小人开始,依次数完 mm 条指令后到达的小人的职业。
输入输出样例
输入 #1复制
7 3
0 singer
0 reader
0 mengbier
1 thinker
1 archer
0 writer
1 mogician
0 3
1 1
0 2
输出 #1复制
writer
输入 #2复制
10 10
1 C
0 r
0 P
1 d
1 e
1 m
1 t
1 y
1 u
0 V
1 7
1 1
1 4
0 5
0 3
0 1
1 6
1 2
0 8
0 4
分析:刚开始的想法是用链表来储存这些人(方向,职业),后来发现链表向后读取s个位置很容易但是向前就很棘手了,(也许可以使用双向链表来解决,但是我还没有学习),所有我还是打算用数组来实现,当位置<0或者超出原有的数据范围,要做出相应的变化。
代码:
oj给了80分,有4个测试点re了,不知道啥原因…
#include<stdio.h>
struct people{
int fx;
char job[10];
};
int main()
{
int m,n;//m个人,n条指令
int i,j;
int f,s;
int count=0;//用来记录位置
scanf("%d %d",&m,&n);
struct people p[20000];
for(i=0;i<m;i++)
{
scanf("%d %s",&p[i].fx,p[i].job);
}
for(i=0;i<n;i++)
{
scanf("%d %d",&f,&s);
if(p[count].fx==f)//相等时候逆时针转
{
count-=s;
}
else count+=s;
//判断count位置情况,是否小于零或者大于m
if(count<0)
{
while(count<0)
{
count+=m;
}
}
if(count>=m)
{
while(count>=m)
{
count-=m;
}
}
//printf("%d: %s\n",i,p[count].job);
}
printf("%s",p[count].job);
return 0;
}
3.A+B(高精度)
题目描述
高精度加法,相当于a+b problem,不用考虑负数.
输入格式
分两行输入。a,b \leq 10^{500}a,b≤10
500
输出格式
输出只有一行,代表a+ba+b的值
输入输出样例
输入 #1复制
1
1
输出 #1复制
2
输入 #2复制
1001
9099
输出 #2复制
10100
分析:
先将两个数以字符串形式读入,再转换成数字储存到另外两个数组中去,模拟小学学过的排竖式即可,即同位相加,逢十进一。
代码:
只有60分,挺离谱不知道问题出在哪,感觉思路是没什么问题
#include<stdio.h>
#include<string.h>
char s1[1000],s2[1000];
int a1[1000],a2[1000];
int main()
{
char s1[1000],s2[1000];
int a1[1000],a2[1000];
int i,j,max,cry;
int len1,len2;
scanf("%s %s",s1,s2);
len1=strlen(s1);
len2=strlen(s2);
for(i=0;i<len1;i++)
a1[len1-i-1]=s1[i]-'0';
for(i=0;i<len1;i++)
a2[len2-i-1]=s2[i]-'0';
if(len1>len2) max=len1;
else max=len2;
a1[0]=a1[0]+a2[0];
cry=a1[0]/10;
a1[0]=a1[0]%10;
for(i=1;i<=max;i++)
{
a1[i]=a1[i]+a2[i]+cry;
cry=a1[i]/10;
a1[i]=a1[i]%10;
}
if(a1[max]!=0) printf("%d",a1[max]);
for(i=max-1;i>=0;i--)
printf("%d",a1[i]);
printf("\n");
return 0;
}
注:今天就写了个加法,其实乘法也是相同的原理,模拟列竖式的过程就可以了,只是xue微有的复杂,阶乘或者是阶乘之和就可以直接调用函数,以此类推。
4.魔法少女小Scarlet
题目描述
Scarlet最近学会了一个数组魔法,她会在n*nn∗n二维数组上将一个奇数阶方阵按照顺时针或者逆时针旋转90°,
首先,Scarlet会把11到n^2n 2 的正整数按照从左往右,从上至下的顺序填入初始的二维数组中,然后她会施放一些简易的魔法。
Scarlet既不会什么分块特技,也不会什么Splay套Splay,她现在提供给你她的魔法执行顺序,想让你来告诉她魔法按次执行完毕后的二维数组。
输入格式
第一行两个整数n,mn,m,表示方阵大小和魔法施放次数。
接下来mm行,每行44个整数x,y,r,zx,y,r,z,表示在这次魔法中,Scarlet会把以第xx行第yy列为中心的2r+12r+1阶矩阵按照某种时针方向旋转,其中z=0z=0表示顺时针,z=1z=1表示逆时针。
输出格式
输出nn行,每行nn个用空格隔开的数,表示最终所得的矩阵
输入输出样例
输入 #1复制
5 4
2 2 1 0
3 3 1 1
4 4 1 0
3 3 2 1
输出 #1复制
5 10 3 18 15
4 19 8 17 20
1 14 23 24 25
6 9 2 7 22
11 12 13 16 21
说明/提示
对于50%的数据,满足r=1r=1
对于100%的数据1\leq n,m\leq5001≤n,m≤500,满足1\leq x-r\leq x+r\leq n,1\leq y-r\leq y+r\leq n1≤x−r≤x+r≤n,1≤y−r≤y+r≤n
思路分析:
其实主要是找到逆时针或者是顺时针旋转90°后对应元素坐标的变化关系即可,然后就是根据每条指令做出对应的变化。
代码实现:
#include<stdio.h>
int a[600][600],f[600][600];//a用来储存主数组,f用来临时储存
int main()
{
int n,m,x,y,r,z,i,j;
int count=1;
scanf("%d %d",&n,&m) ;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
a[i][j]=count;
count++;
}
}
while(m--)
{
scanf("%d %d %d %d",&x,&y,&r,&z);
//下列对操作的描述仅限于那一块矩阵而言
if(z==1)//逆时针 第i行第j个 变成第i列都阿叔第j个
{
for(i=x-r;i<=x+r;i++)
{
for(j=y-r;j<=y+r;j++)
{
f[x+y-j][y-x+i]=a[i][j];
}
}
for(i=x-r;i<=x+r;i++)
{
for(j=y-r;j<=y+r;j++)
a[i][j]=f[i][j];
}
}
else//顺时针 第i行第j个变成倒数第i列第j个
{
//先将那块矩阵变换后存入临时数组中去
for(i=x-r;i<=x+r;i++)
{
for(j=y-r;j<=y+r;j++)
{
f[x-y+j][x+y-i]=a[i][j];
}
}
//再将矩阵放回原矩阵中去
for(i=x-r;i<=x+r;i++)
{
for(j=y-r;j<=y+r;j++)
{
a[i][j]=f[i][j];
}
}
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
return 0;
}
排序
1.STL中的sort函数(永远比你手写的快排或者其他排序要快得多),适合用来打题,节约时间。
(1)对数组元素排序
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
sort(a,a+n,cmp);
}
这时为降序排列,将cmp中的a>b改成a<b即为升序排列。
(2)对结构体排序
只需要把a>b改成比较结构体中的元素。
2.快排,冒泡,选择,插入,希尔,堆排等等经典排序等我下次系统学习后再写博客总结。