2016.8.24.noip2012D1
vigenere:
第一个比较简单的,就是个密码表,我直接把字母对应转化为数字,另一个bool数组确定大小写,然后根据规律写那个方程,完。
game:
事出反常必有妖。然而我之前并没有注意到。一开始就应该注意到,无论被除数还是除数之中都没有一个当前人的左手数。然后在考虑总积不变的规律就应该联想到,通过排列左手右手数的乘积来判断。然而本题之中前一个思路为一点,另一个更重要的地方时数据范围需要使用高精度对单精度的除法、乘法,并且由于数据过大,最好使用万进制。
个人修改后代码如下(并未使用万进制):
#include<iostream> #include<cstring> #include<fstream> #include<algorithm> #define cin fin using namespace std; ifstream fin ("game.in"); ofstream fout ("game.out"); int n,a0,b0,ans[4405],p[4406],prod[4405],divi[4405]; struct stu { int a,b,c; }f[1005]; bool yeah(const stu & q1,const stu &q2) { return q1.c<q2.c; } void pro(int x) { int t=0,i9=0; memset(p,0,sizeof(p)); p[0]=prod[0]; for(int i8=1;i8<=prod[0];i8++) { t=x*prod[i8]; p[i8]+=t;//万一多位进位 i9=i8; while(p[i9]>=10) { p[i9+1]+=p[i9]/10; p[i9]%=10; i9++; } if(i9>p[0])//防止出现42500005而p[0]=3时的特殊情况。 p[0]=i9; } prod[0]=p[0]; while(p[0]) prod[p[0]]=p[p[0]],p[0]--; } void div(int x) { divi[0]=prod[0]; int y=0; for(int i8=prod[0];i8>0;i8--) { y=prod[i8]+10*y; divi[i8]=y/x; y=y%x; } while(divi[divi[0]]==0&&divi[0]>1) divi[0]--; } int main() { cin>>n; cin>>a0>>b0; for(int i=1;i<=n;i++) { cin>>f[i].a>>f[i].b; f[i].c=f[i].a*f[i].b; } sort(f+1,f+n+1,yeah); prod[1]=prod[0]=1; pro(a0); for(int i=1;i<=n;i++) { div(f[i].b); pro(f[i].a); int o=-1; if(divi[0]>=ans[0]) { if(ans[0]==divi[0]) o=0; ans[0]=divi[0]; for(int j=divi[0];j>0;j--) { if(o==0) if(ans[j]<divi[j]) o=1; else if(ans[j]>divi[j]) break; ans[j]=divi[j]; } } } for(int i=ans[0];i>0;i--) fout<<ans[i]; return 0; }
根据此情况,发现高精度算法还需要复习,并且最好使用模板。
drive:
这道题,一开始并没有想到从后往前处理顺序问题(方便查找最近和第二近的),而是愚蠢的用了两个二分查找,费时费力。
之后呐,也并没有想到更好的办法。
后面的处理是用的并不太好的倍增。简直迷醉。倍增次数,不清楚这些人怎么想出来的。
之后倍增总结的时候一并算了吧。