目录:1:vigenere密码【字符】2:国王游戏【贪心】【高精度】3:开车旅行【倍增】【set】
题目:
VJ P1778 vigenere密码
描述
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-'A'+ki-'A')mod26+'A',运算@的规则如下表所示:
例如,明文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
Vigenere加密在操作时需要注意:
1. @运算忽略参与运算的字母的大小写,并保持字母在明文M中的大小写形式;
2. 当明文M的长度大于密钥k的长度时,将密钥k重复使用。
格式
输入格式
输入共2行。
第一行为一个字符串,表示密钥k,长度不超过100,其中仅包含大小写字母。第二行为一个字符串,表示经加密后的密文,长度不超过1000,其中仅包含大小写字母。
输出格式
输出共1行,一个字符串,表示输入密钥和密文所对应的明文。
限制
每个测试点1s
提示
对于100%的数据,输入的密钥的长度不超过100,输入的密文的长度不超过1000,且都仅包含英文字母。
VJ P1779 国王游戏
描述
恰逢H国国庆,国王邀请n位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这n位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
格式
输入格式
第一行包含一个整数n,表示大臣的人数。
第二行包含两个整数a和b,之间用一个空格隔开,分别表示国王左手和右手上的整数。接下来n行,每行包含两个整数a和b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出格式
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
限制
每个测试点1s
提示
对于20%的数据,有1≤ n≤ 10,0 < a、b < 8;
对于40%的数据,有1≤ n≤20,0 < a、b < 8;
对于60%的数据,有1≤ n≤100;
对于60%的数据,保证答案不超过10^9;
对于100%的数据,有1 ≤ n ≤1,000,0 < a、b < 10000。
VJ P1780 开车旅行
描述
小A和小B决定利用假期外出旅行,他们将想去的城市从1到N编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市i 的海拔高度为Hi,城市i 和城市j 之间的距离d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i,j] = |Hi - Hj|。
旅行过程中,小A和小B轮流开车,第一天小A开车,之后每天轮换一次。他们计划选择一个城市S作为起点,一直向东行驶,并且最多行驶X公里就结束旅行。小A和小B的驾驶风格不同,小B总是沿着前进方向选择一个最近的城市作为目的地,而小A总是沿着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出X公里,他们就会结束旅行。
在启程之前,小A想知道两个问题:
1.对于一个给定的X=X0,从哪一个城市出发,小A开车行驶的路程总数与小B行驶的路程总数的比值最小(如果小B的行驶路程为0,此时的比值可视为无穷大,且两个无穷大视为相等)。如果从多个城市出发,小A开车行驶的路程总数与小B行驶的路程总数的比值都最小,则输出海拔最高的那个城市。
2. 对任意给定的X=Xi 和出发城市Si,小A开车行驶的路程总数以及小B行驶的路程总数。
格式
输入格式
第一行包含一个整数N,表示城市的数目。
第二行有N个整数,每两个整数之间用一个空格隔开,依次表示城市1到城市N的海拔高度,即H1,H2,……,Hn,且每个Hi 都是不同的。
第三行包含一个整数X0。
第四行为一个整数M,表示给定M组Si和Xi。
接下来的M行,每行包含2个整数Si 和Xi,表示从城市Si 出发,最多行驶Xi 公里。
输出格式
输出共M+1行。
第一行包含一个整数S0,表示对于给定的X0,从编号为S0的城市出发,小A开车行驶
的路程总数与小B行驶的路程总数的比值最小。
接下来的M行,每行包含2个整数,之间用一个空格隔开,依次表示在给定的Si 和Xi 下小A行驶的里程总数和小B行驶的里程总数。
样例2
限制
每个测试点1s
提示
对于30%的数据,有1≤N≤20,1≤M≤20;
对于40%的数据,有1≤N≤100,1≤M≤100;
对于50%的数据,有1≤N≤100,1≤M≤1,000;
对于70%的数据,有1≤N≤1,000,1≤M≤10,000;
对于100%的数据,有1≤N≤100,000,1≤M≤10,000,-1,000,000,000≤Hi≤1,000,000,000,0≤X0≤1,000,000,000,1≤Si≤N,0≤Xi≤1,000,000,000,数据保证Hi 互不相同。
题解:
第一题乍一看好像挺复杂的,但其实只要用ASCII码推出计算的公式,就简单多了,然后问题就只有字符处理和把大写字母转换成小/大写字母上了。
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<vector> 6 using namespace std; 7 char s1[105],s2[1005],ans[1005]; 8 bool pos[1005]={false}; 9 int len1,len2; 10 int main() 11 { 12 freopen("vigenere.in","r",stdin); 13 freopen("vigenere.out","w",stdout); 14 cin>>s1;len1=strlen(s1); 15 cin>>s2;len2=strlen(s2); 16 for (int i=0;i<len1;i++) 17 if (s1[i]<97) s1[i]+=32;//转化为小写字母 18 for (int i=0;i<len2;i++) 19 if (s2[i]<97) 20 { 21 pos[i]=true;//记录原来是大写字母的位置 22 s2[i]+=32; 23 } 24 int t=0; 25 while(t<len2) 26 { 27 int p=t; 28 while(p>=len1) p-=len1;//密文长度大于密匙 29 if(s2[t]<s1[p]) ans[t]=123-s1[p]+s2[t]; 30 //例如:s1='d' s2='a' ans=97+(122-s1)+(s2-91+1)=123-s1+s2=120='x' 31 else if (s2[t]==s1[p]) ans[t]='a'; 32 else ans[t]=97+s2[t]-s1[p]; 33 if (pos[t]) ans[t]-=32;//如果原为大写字母则复原 34 t++; 35 } 36 for (int i=0;i<len2;i++) 37 cout<<ans[i]; 38 return 0; 39 }
第二题显然不能找排列方式一一判断。方法:如果要交换A大臣和B 大臣,需要满足的是:L(A)/R(B)>L(B)/R(A),即L(A)*R(A)>L(B)*R(B).所以按照这个规则排序再找最大值就是ans。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 int n,v,e; 6 struct pp{ 7 int l,r,k; 8 }; 9 pp que[1005]; 10 const int/**/ comp(const pp &x,const pp &y) 11 { 12 return x.k<y.k; 13 } 14 struct hp{ 15 int w[10000]; 16 }; 17 hp ans,sum; 18 hp cheng (hp a,int b) 19 { 20 hp c; 21 c.w[0]=a.w[0]+1; 22 for (int i=1;i<=c.w[0];i++) c.w[i]=0; 23 for (int i=1;i<=c.w[0];i++) 24 { 25 c.w[i]+=a.w[i]*b; 26 c.w[i+1]+=c.w[i]/10000; 27 c.w[i]%=10000; 28 } 29 while (c.w[0]>0&&c.w[c.w[0]]==0) c.w[0]--; 30 return c; 31 } 32 hp chu(hp a,int b) 33 { 34 hp c; 35 c.w[0]=a.w[0]+1; 36 for (int i=1;i<=c.w[0];i++) c.w[i]=0; 37 int x=0; 38 for (int i=a.w[0];i>=1;i--) 39 { 40 x=x*10000+a.w[i]; 41 c.w[i]=x/b; 42 x%=b; 43 } 44 while(c.w[0]>0&&c.w[c.w[0]]==0) c.w[0]--; 45 return c; 46 } 47 hp bj(hp a,hp b) 48 { 49 if (a.w[0]>b.w[0]) return a; 50 if (a.w[0]<b.w[0]) return b; 51 for (int i=a.w[0];i>=1;i--) 52 { 53 if (a.w[i]>b.w[i]) return a; 54 if (a.w[i]<b.w[i]) return b; 55 } 56 return a; 57 } 58 int main() 59 { 60 freopen("game.in","r",stdin); 61 freopen("game.out","w",stdout); 62 cin>>n; 63 cin>>v>>e; 64 for (int i=1;i<=n+1;i++) 65 { 66 scanf("%d%d",&que[i].l,&que[i].r); 67 que[i].k=que[i].l*que[i].r; 68 } 69 sort(que+1,que+1+n,comp); 70 sum.w[0]=1; 71 sum.w[1]=v; 72 for (int i=1;i<=n;i++) 73 { 74 ans=bj(ans,chu(sum,que[i].r)); 75 sum=cheng(sum,que[i].l); 76 } 77 printf("%d",ans.w[ans.w[0]]); 78 for (int i=ans.w[0]-1;i>=1;i--) printf("%04d",ans.w[i]); 79 return 0; 80 }
第三题如果纯模拟并且初始了第一第二近的城市可以过70。满分是用 set初始+倍增过程。具体做法解释可以参照http://blog.csdn.net/nilihan1999/article/details/37809903
1 #include<iostream> 2 #include<cstdio> 3 #include<set> 4 #include<algorithm> 5 #include<cmath> 6 #define LL long long 7 #ifdef WIN32 8 #define AUTO "%I64d %I64d " 9 #else 10 #define AUTO "%lld %lld " 11 #endif 12 using namespace std; 13 const int maxn=100005; 14 struct pp{ 15 int h,num; 16 bool operator < (const pp rr) const 17 { 18 return h<rr.h; 19 } 20 }; 21 pp city[maxn]; 22 set<pp> s; 23 set<pp>::iterator it; 24 int n,m,x0; 25 int to[maxn][2],dis[maxn][2],g[maxn][21]; 26 LL f[maxn][21][2];//0:B 1:A 27 void find_near(pp x,pp y) 28 { 29 int d=abs(x.h-y.h); 30 if (!to[x.num][0]) 31 { 32 to[x.num][0]=y.num; 33 dis[x.num][0]=d; 34 } 35 else if (d<dis[x.num][0]||(d==dis[x.num][0]&&y.h<city[to[x.num][0]].h)) 36 { 37 to[x.num][1]=to[x.num][0]; 38 dis[x.num][1]=dis[x.num][0]; 39 dis[x.num][0]=d; 40 to[x.num][0]=y.num; 41 } 42 else if (d<dis[x.num][1]||(d==dis[x.num][1]&&y.h<city[to[x.num][1]].h)) 43 { 44 to[x.num][1]=y.num; 45 dis[x.num][1]=d; 46 } 47 else if (!to[x.num][1]) 48 { 49 to[x.num][1]=y.num; 50 dis[x.num][1]=d; 51 } 52 return ; 53 } 54 void find_way() 55 { 56 for (int i=n;i>=1;i--) 57 { 58 s.insert(city[i]); 59 it=s.find(city[i]); 60 if (it!=s.begin()) 61 { 62 it--; 63 find_near(city[i],*it); 64 if (it!=s.begin()) 65 { 66 it--; 67 find_near(city[i],*it); 68 it++; 69 } 70 it++; 71 } 72 if ((++it)!=s.end()) 73 { 74 find_near(city[i],*it); 75 if ((++it)!=s.end()) 76 { 77 find_near(city[i],*it); 78 it--; 79 } 80 it--; 81 } 82 } 83 } 84 void begin() 85 { 86 for (int i=1;i<=n;i++) 87 { 88 g[i][0]=to[to[i][1]][0]; 89 f[i][0][1]=dis[i][1]; 90 f[i][0][0]=dis[to[i][1]][0]; 91 } 92 for (int j=1;j<=20;j++) 93 for (int i=1;i<=n;i++) 94 { 95 g[i][j]=g[g[i][j-1]][j-1]; 96 f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1]; 97 f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0]; 98 } 99 } 100 void query(int s,int x,LL &disa,LL &disb) 101 { 102 for (int i=20;i>=0;i--)// >= 0 103 if (f[s][i][0]+f[s][i][1]<=x&&g[s][i]) 104 { 105 disa+=f[s][i][1]; 106 disb+=f[s][i][0]; 107 x-=f[s][i][0]+f[s][i][1]; 108 s=g[s][i]; 109 } 110 if (to[s][1]&&dis[s][1]<=x) 111 disa+=dis[s][1]; 112 } 113 int main() 114 { 115 freopen("drive.in","r",stdin); 116 freopen("drive.out","w",stdout); 117 cin>>n; 118 for (int i=1;i<=n;i++) 119 { 120 scanf("%d",&city[i].h); 121 city[i].num=i; 122 } 123 find_way(); 124 begin(); 125 cin>>x0; 126 LL a=1000000000,b=0; 127 int ans=0; 128 for (int i=1;i<=n;i++) 129 { 130 LL disa=0,disb=0; 131 query(i,x0,disa,disb); 132 if (disb!=0&&(!ans||a*disb>b*disa)) 133 { 134 a=disa; 135 b=disb; 136 ans=i; 137 } 138 } 139 cout<<ans<<endl; 140 cin>>m; 141 for (int i=1;i<=m;i++) 142 { 143 int s,x; 144 LL disa=0,disb=0; 145 scanf("%d%d",&s,&x); 146 query(s,x,disa,disb); 147 printf(AUTO,disa,disb); 148 } 149 return 0; 150 }
这毕竟是放了一个月暑假返校后的第一次测试,暑假本来计划的一切都没有完成,什么刷题啊、复习啊..既然荒废了一个月,那么再联赛前的这两个多月里,就要更加努力了。
这次考试分数太差,第一题把'A'放在s1==s2的情况,又多剪了一个32,导致所有A都输成了'!'。。
第二题直接用L(i)排序去了,只过了30。
第三题到考试结束时还没有调出来,所以。。
总结:要加快做题速度,加强算法练习,注意小问题。