期望得分:100+100+70=270
实际得分:100+50+70=220
T2 没有底
最后剩余时间来不及打高精、思路出现错误
T1 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 加密在操作时需要注意:
-
®运算忽略参与运算的字母的大小写,并保持字母在明文 M 中的大小写形式;
- 当明文 M 的长度大于密钥 k 的长度时,将密钥 k 重复使用。
例如,明文 M=Helloworld,密钥 k=abc 时,密文 C=Hfnlpyosnd。
输入输出格式
输入格式:
输入共 2 行。
第一行为一个字符串,表示密钥 k,长度不超过 100,其中仅包含大小写字母。第二行为一个字符串,表示经加密后的密文,长度不超过 1000,其中仅包含大小写字母。
输出格式:
输出共 1 行,一个字符串,表示输入密钥和密文所对应的明文。
输入输出样例
CompleteVictory Yvqgpxaimmklongnzfwpvxmniytm
Wherethereisawillthereisaway
说明
【数据说明】
对于 100%的数据,输入的密钥的长度不超过 100,输入的密文的长度不超过 1000,且都仅包含英文字母。
定义字符ch的ASCLL码为 a(ch)
则a(明文)= [a(密文)+26-a(密匙)]%26+1
#include<cstdio> #include<cstring> using namespace std; char a[101],b[1001]; void change(int i) { if(a[i]<='Z') return; a[i]-=32; } int main() { /*freopen("vigenere.in","r",stdin); freopen("vigenere.out","w",stdout);*/ scanf("%s%s",a,b); int lena=strlen(a); for(int i=0;i<lena;i++) change(i); int lenb=strlen(b),j=0; int x,y,z; for(int i=0;i<lenb;i++) { if(j==lena) j=0; x=a[j]-'A'+1; y=b[i]>=97 ? b[i]-'a'+1 : b[i]-'A'+1; z=(y+26-x)%26+1; z=b[i]>=97 ? z+97-1:z+65-1; putchar(z); j++; } }
T2 国王游戏
题目描述
恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。
输入输出格式
输入格式:
第一行包含一个整数 n,表示大臣的人数。
第二行包含两个整数 a和 b,之间用一个空格隔开,分别表示国王左手和右手上的整数。
接下来 n 行,每行包含两个整数 a 和 b,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
输出格式:
输出只有一行,包含一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。
输入输出样例
3 1 1 2 3 7 4 4 6
2
说明
【输入输出样例说明】
按 1、2、3 号大臣这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 1、3、2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 2、1、3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 2、3、1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9;
按 3、1、2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2;
按 3、2、1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9。
因此,奖赏最多的大臣最少获得 2 个金币,答案输出 2。
【数据范围】
对于 20%的数据,有 1≤ n≤ 10,0 < a、b < 8;
对于 40%的数据,有 1≤ n≤20,0 < a、b < 8;
对于 60%的数据,有 1≤ n≤100;
对于 60%的数据,保证答案不超过 109;
对于 100%的数据,有 1 ≤ n ≤1,000,0 < a、b < 10000。
题意:改变序列中大臣的顺序
使最大的 ( ∏ left[i] ) / right[j] i<j 最小
分析得交换相邻两个大臣i和j的位置,对i前面前面的结果没有影响,对j后面的结果也没有影响
只会影响i和j的结果
定义m为大臣获得的金币数,s= ∏ left[k] 1<=k<i
A、 i 在 j 前面
m(i)= s / right[i] ① m(j)= s * left[i] / right[j] ②
B、j 在 i 前面
m(i)= s * left[j] / right[i] ③ m(j)= s / right[j] ④
① <③ ④ < ②
题意要从A中选最大的m,设其为a,B中选最大的m,设其为b。ans=min(a,b)
若 ① > ② ,③ > ④ ,则a=①,b=③ ∵①<③ ∴方案A更优 由①②得,left[i] * right[i] < right[j],i在前
若 ① > ② ,③ < ④ ,那么 ③ > ① > ② > ④ > ③ 不存在
若 ① < ② ,③ > ④ , 那么a=② ,b=③
如果 a<b,此时方案A更优,由②③得, left[i]* right[i]< left[j]* right[j], i在前
如果 a>b,此时方案B更优,由②③的,left[j]* right[j]<left[i]* right[i] , j在前
若 ① < ② ,③ < ④,那么a=②,b=④ ∵ ④ < ② ∴方案B更优 由③④得,left[j] * right[j] < right[i] ,j在前
所以每次都是left*right小的在前
所以解法:按左右手乘积从小到大排序,然后一个一个算,取最大的
再就是要高精度
AC代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,aa,bb,a[51001],b[51001],c[51001],ans[51001],tmp[51001],d,kk[51001]; int x; struct node { int l,r; }e[1001]; bool cmp3(node p,node q) { return p.l*p.r<q.l*q.r; } void mul() { memset(c,0,sizeof(c)); for(int i=1;i<=a[0];i++) { for(int j=1;j<=b[0];j++) { x=c[i+j-1]+a[i]*b[j]; c[i+j-1]=x%10; c[i+j]+=x/10; } } c[0]=a[0]+b[0]; while(!c[c[0]]&&c[0]>1) c[0]--; for(int i=0;i<=c[0];i++) a[i]=c[i]; a[0]=c[0]; } void divide() { x=0; for(int i=1;i<=a[0];i++) { x=x*10+a[i]; c[i]=x/d; x=x%d; } int i; for(i=1;i<a[0];i++) if(c[i]) break; tmp[0]=0; for(int j=i;j<=a[0];j++) tmp[++tmp[0]]=c[j]; } void change(int i) { b[0]=0; while(i) { b[++b[0]]=i%10; i/=10; } } void cmp() { if(tmp[0]>ans[0]) { for(int i=0;i<=tmp[0];i++) ans[i]=tmp[i]; } else if(tmp[0]==ans[0]) { for(int i=1;i<=tmp[0];i++) { if(tmp[i]>ans[i]) { for(int j=i;j<=tmp[0];j++) ans[j]=tmp[j]; } else if(tmp[i]<ans[i]) return; } } } void reverse(int *p) { kk[0]=0; for(int i=p[0];i>=1;i--) kk[++kk[0]]=p[i]; for(int i=0;i<=kk[0];i++) p[i]=kk[i]; } int main() { freopen("kinggame.in","r",stdin); freopen("kinggame.out","w",stdout); scanf("%d",&n); scanf("%d%d",&aa,&bb); for(int i=1;i<=n;i++) scanf("%d%d",&e[i].l,&e[i].r); sort(e+1,e+n+1,cmp3); int t=aa/e[1].r; while(t) { ans[++ans[0]]=t%10; t/=10; } reverse(ans); while(aa) { a[++a[0]]=aa%10; aa/=10; } reverse(a); for(int i=1;i<n;i++) { change(e[i].l); reverse(a); mul(); reverse(a); d=e[i+1].r; divide(); cmp(); } for(int i=1;i<=ans[0];i++) printf("%d",ans[i]); }
自己做的时候,没推出结论,四种贪心按a排,按b排,按a+b排,按a*b排取最优
没写高精度拿了50,因为误认为最大的一定是最后一个
#include<cstdio> #include<algorithm> using namespace std; int n,a,b; long long ans=1e17,t; double tt; bool ok; struct node { int l,r; }tmp[1000001]; bool cmp1(node p,node q) { return p.r<q.r; } bool cmp2(node p,node q) { return p.l<q.l; } bool cmp3(node p,node q) { return p.l*p.r<q.l*q.r; } bool cmp4(node p,node q) { return p.l+p.r<q.l+q.r; } int main() { freopen("kinggame.in","r",stdin); freopen("kinggame.out","w",stdout); scanf("%d",&n); scanf("%d%d",&a,&b); for(int i=1;i<=n;i++) scanf("%d%d",&tmp[i].l,&tmp[i].r); t=a;tt=a;ok=false; sort(tmp+1,tmp+n+1,cmp1); for(int i=1;i<n;i++) { if(tt*tmp[i].l>1e9) { ok=true; break;} tt*=tmp[i].l;t*=tmp[i].l; } if(!ok) ans=t/tmp[n].r; t=a;tt=a;ok=false; sort(tmp+1,tmp+n+1,cmp2); for(int i=1;i<n;i++) { if(tt*tmp[i].l>1e9) { ok=true; break;} tt*=tmp[i].l;t*=tmp[i].l; } if(!ok) ans=min(ans,t/tmp[n].r); t=a;tt=a;ok=false; sort(tmp+1,tmp+n+1,cmp3); for(int i=1;i<n;i++) { if(tt*tmp[i].l>1e9) { ok=true; break;} tt*=tmp[i].l;t*=tmp[i].l; } if(!ok) ans=min(ans,t/tmp[n].r); t=a;tt=a;ok=false; sort(tmp+1,tmp+n+1,cmp4); for(int i=1;i<n;i++) { if(tt*tmp[i].l>1e9) { ok=true; break;} tt*=tmp[i].l;t*=tmp[i].l; } if(!ok) ans=min(ans,t/tmp[n].r); printf("%lld",ans); }
高精度把数组改成了字符数组,然后就挂了
挂了的代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n; string aa,bb,a,b; string ans(41001,'