模拟
Wikioi 1314 寻宝
传说很遥远的藏宝楼顶层藏着诱人的宝藏。小明历尽千辛万苦终于找到传说中的这个藏宝楼,藏宝楼的门口竖着一个木板,上面写有几个大字:寻宝说明书。说明书的内容如下:
藏宝楼共有N+1层,最上面一层是顶层,顶层有一个房间里面藏着宝藏。除了顶层外,藏宝楼另有N层,每层M个房间,这M个房间围成一圈并按逆时针方向依次编号为0,…,M-1。其中一些房间有通往上一层的楼梯,每层楼的楼梯设计可能不同。每个房间里有一个指示牌,指示牌上有一个数字x,表示从这个房间开始按逆时针方向选择第x个有楼梯的房间(假定该房间的编号为k),从该房间上楼,上楼后到达上一层的k号房间。比如当前房间的指示牌上写着2,则按逆时针方向开始尝试,找到第2个有楼梯的房间,从该房间上楼。如果当前房间本身就有楼梯通向上层,该房间作为第一个有楼梯的房间。
寻宝说明书的最后用红色大号字体写着:“寻宝须知:帮助你找到每层上楼房间的指示牌上的数字(即每层第一个进入的房间内指示牌上的数字)总和为打开宝箱的密钥”。
请帮助小明算出这个打开宝箱的密钥。
第一行2个整数N和M,之间用一个空格隔开。N表示除了顶层外藏宝楼共N层楼,M表示除顶层外每层楼有M个房间。
接下来N*M行,每行两个整数,之间用一个空格隔开,每行描述一个房间内的情况,其中第(i-1)*M+j行表示第i层j-1号房间的情况(i=1,2,…, N;j=1,2,…,M)。第一个整数表示该房间是否有楼梯通往上一层(0表示没有,1表示有),第二个整数表示指示牌上的数字。注意,从j号房间的楼梯爬到上一层到达的房间一定也是j号房间。
最后一行,一个整数,表示小明从藏宝楼底层的几号房间进入开始寻宝(注:房间编号从0开始)。
输出只有一行,一个整数,表示打开宝箱的密钥,这个数可能会很大,请输出对20123取模的结果即可。
2 3
1 2
0 3
1 4
0 1
1 5
1 2
1
5
【输入输出样例说明】
第一层:
0号房间,有楼梯通往上层,指示牌上的数字是2;
1号房间,无楼梯通往上层,指示牌上的数字是3;
2号房间,有楼梯通往上层,指示牌上的数字是4;
第二层:
0号房间,无楼梯通往上层,指示牌上的数字是1;
1号房间,有楼梯通往上层,指示牌上的数字是5;
2号房间,有楼梯通往上层,指示牌上的数字是2;
小明首先进入第一层(底层)的1号房间,记下指示牌上的数字为3,然后从这个房间开始,沿逆时针方向选择第3个有楼梯的房间2号房间进入,上楼后到达第二层的2号房间,记下指示牌上的数字为2,由于当前房间本身有楼梯通向上层,该房间作为第一个有楼梯的房间。因此,此时沿逆时针方向选择第2个有楼梯的房间即为1号房间,进入后上楼梯到达顶层。这时把上述记下的指示牌上的数字加起来,即3+2=5,所以打开宝箱的密钥就是5。
【数据范围】
对于50%数据,有0<N≤1000,0<x≤10000;
对于100%数据,有0<N≤10000,0<M≤100,0<x≤1,000,000。
思路:
按照题目模拟上楼过程,注意取余
代码:
1 #include<iostream> 2 #include<cmath> 3 using namespace std; 4 bool stair[10000][100]; 5 int issta[10000]; 6 int x[10000][100]; 7 int main() 8 { 9 int n,m,k=0; 10 cin>>n>>m; 11 for(int i=0;i<n;i++) 12 for(int j=0;j<m;j++) 13 cin>>stair[i][j]>>x[i][j]; 14 for(int i=0;i<n;i++) 15 for(int j=0;j<m;j++) 16 { 17 if(stair[i][j]==1) 18 issta[i]++; 19 } 20 cin>>k; 21 int sum=0; 22 for(int i=0;i<n;i++) 23 { 24 int temp=((x[i][k]%issta[i]!=0)?(x[i][k]%issta[i]):issta[i]); 25 int flag=0; 26 sum+=x[i][k]; 27 for(int j=k;j<2*m;j++) 28 { 29 if(stair[i][j%m]==1) 30 flag++; 31 if(flag==temp) 32 { 33 k=j%m; 34 break; 35 } 36 } 37 } 38 cout<<sum%20123<<endl; 39 return 0; 40 }
Wikioi 1127 接水问题
学校里有一个水房,水房里一共装有m 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为1。
现在有n 名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从1到n 编号,i 号同学的接水量为wi。接水开始时,1 到m 号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学j 完成其接水量要求wj 后,下一名排队等候接水的同学k马上接替j 同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即j 同学第x 秒结束时完成接水,则k 同学第x+1 秒立刻开始接水。若当前接水人数n’不足m,则只有n’个龙头供水,其它m−n’个龙头关闭。
现在给出n 名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。
第1 行2 个整数n 和m,用一个空格隔开,分别表示接水人数和龙头个数。
第2 行n 个整数w1、w2、……、wn,每两个整数之间用一个空格隔开,wi 表示i 号同
学的接水量。
输出只有一行,1 个整数,表示接水所需的总时间。
5 3
4 4 1 2 1
4
n<=10000, m<=100
第1 秒,3 人接水。第1 秒结束时,1、2、3 号同学每人的已接水量为1,3 号同学接完水,4 号同学接替3 号同学开始接水。
第2 秒,3 人接水。第2 秒结束时,1、2 号同学每人的已接水量为2,4 号同学的已接水量为1。
第3 秒,3 人接水。第3 秒结束时,1、2 号同学每人的已接水量为3,4 号同学的已接水量为2。4 号同学接完水,5 号同学接替4 号同学开始接水。
第4 秒,3 人接水。第4 秒结束时,1、2 号同学每人的已接水量为4,5 号同学的已接水量为1。1、2、5 号同学接完水,即所有人完成接水。
总接水时间为4 秒。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 5 const int maxm = 101; 6 using namespace std; 7 int main(){ 8 int n = 0,m = 0,rap[maxm],i = 0,r = 0,j = 0,k = 0,l = 0,time = 0,base = 0; 9 scanf("%d",&n); 10 scanf("%d",&m); 11 for(i = 0;i < m;i++) scanf("%d",&rap[i]); 12 sort(rap,rap + m); 13 while((k < n - m) && (scanf("%d",&r) == 1)){ 14 rap[0] += r; 15 sort(rap,rap + m); 16 } 17 cout<<rap[m - 1]<<endl; 18 return 0; 19 }
Wikioi 1197 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。
明文 |
H |
e |
l |
l |
o |
w |
o |
r |
l |
D |
密钥 |
a |
b |
c |
a |
b |
c |
a |
b |
c |
a |
密文 |
H |
f |
n |
l |
p |
y |
o |
s |
n |
d |
输入共2行。
第一行为一个字符串,表示密钥k,长度不超过100,其中仅包含大小写字母。第二为一个字符串,表示经加密后的密文,长度不超过1000,其中仅包含大小写字母
输出共1行,一个字符串,表示输入密钥和密文所对应的明文
CompleteVictory
Yvqgpxaimmklongnzfwpvxmniytm
Wherethereisawillthereisaway
对于 100%的数据,输入的密钥的长度不超过 100,输入的密文的长度不超过 1000,且都仅包含英文字母。
思路:
找出规律来模拟,注意字母大小写
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #define mx 2000 7 using namespace std; 8 char k[mx],sun[mx],moon[mx]; 9 int sign[mx]; 10 int main(){ 11 cin>>k>>moon; 12 for(int i = 0;i < strlen(moon);i++){ 13 if(moon[i] >= 97) { 14 moon[i] -= 32; 15 sign[i] = 1; 16 } else{ 17 sign[i] = 0; 18 } 19 } 20 for(int i = 0;i < strlen(k);i++){ 21 if(k[i] >= 97) k[i] -= 32; 22 } 23 for(int i = 0;i < strlen(moon);i++){ 24 int j = i % strlen(k); 25 sun[i] = moon[i] - ((k[j] - 65) % 31); 26 if(sun[i] < 65) sun[i] += 26; 27 if(sign[i]) sun[i] += 32; 28 } 29 cout<<sun<<endl; 30 return 0; 31 }
Wikioi 3730 无线网络发射选址
随着智能手机的日益普及,人们对无线网的需求日益增大。某城市决定对城市内的公共场所覆盖无线网。
假设该城市的布局为由严格平行的129条东西向街道和129条南北向街道所形成的网格状,并且相邻的平行街道之间的距离都是恒定值1。东西向街道从北到南依次编号为0,1,2…128,南北向街道从西到东依次编号为0,1,2…128。
东西向街道和南北向街道相交形成路口,规定编号为x的南北向街道和编号为y的东西向街道形成的路口的坐标是(x, y)。 在 某 些 路 口 存 在 一 定 数 量 的 公 共 场 所 。
由于政府财政问题,只能安装一个大型无线网络发射器。该无线网络发射器的传播范围是一个以该点为中心,边长为2*d的正方形。传播范围包括正方形边界。
例如下图是一个d = 1的无线网络发射器的覆盖范围示意图。
现在政府有关部门准备安装一个传播参数为d的无线网络发射器,希望你帮助他们在城市内找出合适的安装地点,使得覆盖的公共场所最多。
输入文件名为wireless.in。
第一行包含一个整数d,表示无线网络发射器的传播距离。
第二行包含一个整数n,表示有公共场所的路口数目。
接下来n行,每行给出三个整数x, y, k, 中间用一个空格隔开,分别代表路口的坐标(x, y)以及该路口公共场所的数量。同一坐标只会给出一次。
输出文件名为wireless.out。
输出一行,包含两个整数,用一个空格隔开,分别表示能覆盖最多公共场所的安装地点方案数,以及能覆盖的最多公共场所的数量。
wireless.in |
wireless.out |
1 2 4 4 10 6 6 20 |
1 30 |
见上。
对于100%的数据,1 ≤ d ≤ 20,1 ≤ n ≤ 20, 0 ≤ x ≤ 128, 0 ≤ y ≤ 128, 0 < k ≤ 1,000,000。
思路:
本来还在想优化,一看这数据范围直接枚举
代码:
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int a[130][130],d,n,x,y,z,num,ans=-2147483647; 5 int main() 6 { 7 scanf("%d%d",&d,&n); 8 for(int i=1;i<=n;i++) 9 { 10 scanf("%d%d%d",&x,&y,&z); 11 a[x][y]=z; 12 } 13 for(int i=0;i<=128;i++) 14 for(int j=0;j<=128;j++) 15 { 16 int limitx=min(128,i+d),limity=min(128,j+d),cnt=0; 17 for(int k=max(0,i-d);k<=limitx;k++) 18 for(int l=max(0,j-d);l<=limity;l++) 19 cnt+=a[k][l]; 20 if(cnt>ans) 21 { 22 ans=cnt; 23 num=1; 24 } 25 else if(cnt==ans) num++; 26 } 27 printf("%d %d\n",num,ans); 28 return 0; 29 }
Wikioi 3776 生活大爆炸版石头剪子布
石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头。如果两个人出拳一样,则不分胜负。在《生活大爆炸》第二季第8集中出现了一种石头剪刀布的升级版游戏。升级版游戏在传统的石头剪刀布游戏的基础上,增加了两个新手势:
斯波克:《星际迷航》主角之一。 蜥蜴人:《星际迷航》中的反面角色。
这五种手势的胜负关系如表一所示,表中列出的是甲对乙的游戏结果。
现在,小A和小B尝试玩这种升级版的猜拳游戏。已知他们的出拳都是有周期性规律的,但周期长度不一定相等。例如:如果小A以“石头-布-石头-剪刀-蜥蜴人-斯波克”长度为6的周期出拳,那么他的出拳序列就是“石头-布-石头-剪刀-蜥蜴人-斯波克-石头-布-石头-剪刀-蜥蜴人-斯波克-„„”,而如果小B以“剪刀-石头-布-斯波克-蜥蜴人”长度为5的周期出拳,那么他出拳的序列就是“剪刀-石头-布-斯波克-蜥蜴人-剪刀-石头-布-斯波克-蜥蜴人-„„”
已知小A和小B一共进行N次猜拳。每一次赢的人得1分,输的得0分;平局两人都得0分。现请你统计N次猜拳结束之后两人的得分。
输入文件名为rps.in。
第一行包含三个整数:N,NA,NB,分 别 表 示 共 进 行N次猜拳、小A出拳的周期长度,小B出拳的周期长度。数与数之间以一个空格分隔。
第二行包含NA个整数,表示小A出拳的规律,第三行包含NB个整数,表示小B出拳的规律。其中,0表示“剪刀”,1表示“石头”,2表示“布”,3表示“蜥蜴人”, 4表示“斯波克”。数与数之间以一个空格分隔。
输出文件名为rps.out。
输出一行, 包含两个整数,以一个空格分隔,分别表示小A、小B的得分。
对于100%的数据,0 < N ≤ 200,0 < NA ≤ 200, 0 < NB ≤ 200。
思路:
像这种题预处理一下,然后直接输出就可以
代码:
1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 const int maxn = 1000; 6 int ao[maxn],bo[maxn],n,na,nb,sa= 0,sb = 0; 7 int ja[5][5] = {{0,0,1,1,0},{1,0,0,1,0},{0,1,0,0,1},{0,0,1,0,1},{1,1,0,0,0}}; 8 int jb[5][5] = {{0,1,0,0,1},{0,0,1,0,1},{1,0,0,1,0},{1,1,0,0,0},{0,0,1,1,0}}; 9 10 int main(){ 11 cin>>n>>na>>nb; 12 for(int i = 0;i < na;i++) cin>>ao[i]; 13 for(int i = 0;i < nb;i++) cin>>bo[i]; 14 for(int i = 0;i < n;i++){ 15 sb += ja[bo[i % nb]][ao[i % na]]; 16 sa += jb[bo[i % nb]][ao[i % na]]; 17 18 } 19 cout<<sa<<" "<<sb<<endl; 20 return 0; 21 }