周末没事干,就不要脸地去一边吃饭一边看学弟沈阳拿银一边水了个比赛,水都水了,简单写个题解。
A,丁姐姐喜欢Fibonacci。签到1,斐波那契%3 1 1 0 1 1 0 1 1 0。。。,判断模3等于0就好了
1 #include<cstdio> 2 typedef long long ll; 3 int main(){ 4 ll n; 5 while(~scanf("%lld",&n)){ 6 if(n%3==0) printf("\"odd\"\n"); 7 else printf("\"even\"\n"); 8 } 9 return 0; 10 }
B.丁姐姐喜欢LCS。签到2.找最长的首尾相接的,那直接枚举答案的长度,然后进行暴力匹配。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 const int N=2e3+11; 6 char a[N],b[N]; 7 int main(){ 8 while(~scanf("%s%s",a+1,b+1)){ 9 int lena=strlen(a+1),lenb=strlen(b+1),ans=0; 10 for(int i=min(lena,lenb),j;i>=1;i--){ 11 for(j=1;j<=i;j++) if(b[j]!=a[lena-i+j]) break; 12 if(j>i){ 13 ans=i; 14 break; 15 } 16 } 17 if(ans==0) printf("\"NULL!\""); 18 else for(int i=1;i<=ans;i++) printf("%c",b[i]); 19 printf("\n"); 20 } 21 return 0; 22 }
C.俏兔子大战傻贼鹰-Easy Version。简单模拟,判断一下有三张的牌的个数还有两张牌的个数即可,话说数据有点水,居然没有六张一样的牌
1 #include<cstdio> 2 #include<cstring> 3 char op,s[52]; 4 int num[10][5]; 5 int main(){ 6 int t,lens; 7 while(~scanf("%d",&t)){ 8 getchar(); 9 scanf("%c",&op); 10 while(t--){ 11 scanf("%s",s); 12 lens=strlen(s); 13 bool flag=true; 14 for(int i=0;i<lens;i+=2){ 15 int op1=s[i]-'0',op2; 16 if(s[i+1]=='S') op2=0; 17 else if(s[i+1]=='T') op2=1; 18 else op2=2; 19 num[op1][op2]++; 20 if(s[i+1]==op){ 21 flag=false; 22 break; 23 } 24 } 25 int num1=0,num2=0; 26 for(int i=1;i<=9;i++) 27 for(int j=0;j<3;j++){ 28 if(num[i][j]==3) num1++; 29 else if(num[i][j]==2) num2++; 30 num[i][j]=0; 31 } 32 if(flag&&((num1==4&&num2==1)||num2==7)) printf("Yes\n"); 33 else printf("No\n"); 34 } 35 } 36 return 0; 37 }
D.俏兔子大战傻贼鹰-Hard Version。简单模拟2,改一下判断条件那里即可,优先三张连续的再考虑三张一样的。
1 #include<cstdio> 2 #include<cstring> 3 char op,s[52]; 4 int num[10][5]; 5 int main(){ 6 int t,lens; 7 while(~scanf("%d",&t)){ 8 getchar(); 9 scanf("%c",&op); 10 while(t--){ 11 scanf("%s",s); 12 lens=strlen(s); 13 bool flag=true; 14 for(int i=0;i<lens;i+=2){ 15 int op1=s[i]-'0',op2; 16 if(s[i+1]=='S') op2=0; 17 else if(s[i+1]=='T') op2=1; 18 else op2=2; 19 num[op1][op2]++; 20 if(s[i+1]==op){ 21 flag=false; 22 break; 23 } 24 } 25 int num1=0,num2=0; 26 for(int i=1;i<=9;i++) 27 for(int j=0;j<3;j++){ 28 if(i<=7){ 29 while(num[i][j]&&num[i+1][j]&&num[i+2][j]){ 30 num[i][j]--; 31 num[i+1][j]--; 32 num[i+2][j]--; 33 num1++; 34 } 35 } 36 if(num[i][j]>=3) num1++; 37 if(num[i][j]==2) num2++; 38 num[i][j]=0; 39 } 40 if(flag&&((num1==4&&num2==1)||num2==7)) printf("Yes\n"); 41 else printf("No\n"); 42 } 43 } 44 return 0; 45 }
E.[模板]欧拉筛。简单数学题,用不到欧式筛,埃式筛即可,不过我平时都是用欧式筛。入手点,在模数p是1e5级别的数,大于模数的阶乘取模后都为0就不用考虑了,所以先预处理出1e5内素数,然后for到min(n,p)来计算答案就好。
1 #include<cstdio> 2 typedef long long ll; 3 const int N=1e5+11; 4 bool nop[N]; 5 int pn,pri[N]; 6 void init(){ 7 for(int i=2;i<N;i++){ 8 if(!nop[i]) pri[pn++]=i; 9 for(int j=0;j<pn;j++){ 10 if(1ll*i*pri[j]>=N) break; 11 nop[i*pri[j]]=true; 12 if(i%pri[j]==0) break; 13 } 14 } 15 } 16 int main(){ 17 init(); 18 int t,n,p; 19 scanf("%d",&t); 20 while(t--){ 21 scanf("%d%d",&n,&p); 22 ll jc=1,ans=0; 23 for(int i=2;i<=p&&i<=n;i++){ 24 jc=jc*i%p; 25 if(!nop[i]) ans=(ans+jc)%p; 26 } 27 printf("%d\n",ans); 28 } 29 return 0; 30 }
F.[模板]后缀自动机。思维题。要是真的后缀自动机我还真不会。首先我们肯定可以想到是用S的最小后缀去跟T的最小前缀比较即可,S的最小后缀怎么求,后缀自动机?最小表示法?好像都不会,那么我们看T的最小前缀,那不就是第一个字符吗,所以只要判断S中有字典序小于T的第一个字符的字符即可。
1 #include<cstdio> 2 #include<cstring> 3 const int N=2e5+11; 4 char s1[N],s2[N]; 5 int main(){ 6 int t; 7 scanf("%d",&t); 8 while(t--){ 9 scanf("%s%s",s1,s2); 10 int lens1=strlen(s1); 11 bool flag=false; 12 for(int i=lens1-1;i>=0;i--) if(s2[0]>s1[i]){ 13 flag=true; 14 break; 15 } 16 if(flag) printf("YE5\n"); 17 else printf("N0\n"); 18 } 19 return 0; 20 }
G.走迷宫。数学题。可以看出就是螺旋矩阵给出序号求坐标,那么把它划分一层层,第一层的个数就有m+n-1+m-1+n-2也就是2*(n+m-2)个,第二层便是n-2,然后m-2,跟第一场的差便是8个,所以这是个等差数列,那么根据等差数列求和,我们就可以判断出给出的序号在哪一层,然后确定了在哪一层,再根据它在一条边判断即可,需要注意的是n=1,和m=1时的情况。
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 void solve(ll n,ll m,ll k){ 7 if(k>=n*m) k=n*m; 8 ll d=((n+m)*2-ceil(sqrt((n+m)*(n+m)*4-k*16)))/8; 9 d=min(min(n/2,m/2),d); 10 ll x=1+d,y=1+d; 11 k-=(d*(n+m)*4-d*d*8)/2; 12 n-=d*2,m-=d*2; 13 if(!k) y--; 14 else if(n==1) y+=k-1; 15 else if(m==1) x+=k-1; 16 else{ 17 if(k<=m) y+=k-1; 18 else if(k<=n+m-1) y+=m-1,x+=k-m; 19 else if(k<=n+m*2-2) x+=n-1,y+=m*2+n-k-2; 20 else x+=(n+m)*2-k-3; 21 } 22 printf("(%d,%d)\n",x,y); 23 } 24 int main(){ 25 int t,q; 26 ll n,m,k; 27 scanf("%d",&t); 28 while(t--){ 29 scanf("%lld%lld",&n,&m); 30 scanf("%d",&q); 31 while(q--){ 32 scanf("%lld",&k); 33 solve(n,m,k+1); 34 } 35 } 36 return 0; 37 }
H.捡金币。二维前缀和,个人感觉最难的一题吧。根据题意我们要求的就是一个菱形里的点权值和,但我只维护过正的矩形的和,没整过菱形的和,那咋办呢。通过点旋转公式,把整个图形旋转45度,它不就正的了吗,这时再维护这个正的二维前缀和即可。点旋转公式可以自行百度,然后旋转之后原先的坐标(x,y)便成了(√2/2(x+y),√2/2(x-y)),然后我们整体放大√2倍,就成了(x+y,x-y),x-y会存在负数,那便再加上y轴的偏移量,最后便是(x+y,x-y+m),因为k的点的绝对值坐标距离,所以不需要方法√2倍,否则要是两点之间的欧式距离的话,则也需要放大√2倍。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 typedef long long ll; 5 const int N=2e3+11; 6 ll sum[N][N]; 7 int main(){ 8 int t,n,m,q,x,y,k; 9 scanf("%d",&t); 10 while(t--){ 11 scanf("%d%d",&n,&m); 12 for(int i=0;i<=n+m;i++) 13 for(int j=0;j<=n+m;j++) sum[i][j]=0; 14 for(int i=1;i<=n;i++) 15 for(int j=1;j<=m;j++){ 16 x=i+j;y=i-j+m; 17 scanf("%lld",&sum[x][y]); 18 } 19 for(int i=1;i<=n+m;i++) 20 for(int j=1;j<=n+m;j++) 21 sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; 22 scanf("%d",&q); 23 int lx,ly,rx,ry; 24 while(q--){ 25 scanf("%d%d%d",&x,&y,&k); 26 lx=max(1,x+y-k),ly=max(1,x-y+m-k); 27 rx=min(n+m,x+y+k),ry=min(n+m,x-y+m+k); 28 printf("%lld\n",sum[rx][ry]-sum[rx][ly-1]-sum[lx-1][ry]+sum[lx-1][ly-1]); 29 } 30 } 31 return 0; 32 }
I.排序。模拟,弄个结构体,照着题意来即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<tr1/unordered_map> 4 #include<algorithm> 5 using namespace std; 6 const int N=55; 7 struct Node{ 8 string name; 9 int ts,zsj,tj[N],tg[N],sj[N]; 10 bool operator<(const Node &n1)const{ 11 return ts==n1.ts ? (zsj==n1.zsj ? name<n1.name : zsj<n1.zsj): ts>n1.ts; 12 } 13 }a[N]; 14 tr1::unordered_map<string,int> mmp; 15 int main(){ 16 int t,n,m; 17 string s; 18 scanf("%d",&t); 19 while(t--){ 20 scanf("%d%d",&n,&m); 21 mmp.clear(); 22 for(int i=1;i<=m;i++){ 23 cin>>s; 24 a[i].name=s; 25 mmp[s]=i; 26 for(int j=1;j<=n;j++){ 27 a[i].ts=a[i].zsj=0; 28 a[i].tg[j]=a[i].tj[j]=a[i].sj[j]=0; 29 } 30 } 31 int q,id,th,sj; 32 scanf("%d",&q); 33 while(q--){ 34 cin>>s;id=mmp[s]; 35 cin>>sj;cin>>s;th=s[0]-'A'+1; 36 cin>>s; 37 if(a[id].tg[th]) continue; 38 if(s[0]=='A'){ 39 a[id].tg[th]=1;a[id].ts++; 40 a[id].sj[th]=sj; 41 a[id].zsj+=sj+20*a[id].tj[th]; 42 a[id].tj[th]++; 43 }else if(s[0]!='C') a[id].tj[th]++; 44 } 45 sort(a+1,a+1+m); 46 for(int i=1,ra=1;i<=m;i++){ 47 if(i>1&&(a[i].ts!=a[i-1].ts||a[i].zsj!=a[i-1].zsj)) ra=i; 48 cout<<ra<<" "<<a[i].name<<" "<<a[i].ts<<" "<<a[i].zsj; 49 for(int j=1;j<=n;j++){ 50 printf(" "); 51 if(a[i].tg[j]){ 52 printf("+%d(%d)",a[i].tj[j],a[i].sj[j]); 53 }else printf("-%d",a[i].tj[j]); 54 } 55 printf("\n"); 56 } 57 if(t) printf("\n"); 58 } 59 return 0; 60 }
J.n=a*b*c,数学题,由x*y<=n有x<=√n||y<=√n,那么√n枚举两个数,然后求第三个数,再更新一下答案即可。
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 int main(){ 6 int t,n,m; 7 scanf("%d",&t); 8 while(t--){ 9 scanf("%d",&n);m=(int)sqrt(n); 10 int a=0,b=-1,c=n+1,aa,bb,cc; 11 for(int i=2;i<=m;i++) 12 for(int j=2;j<=m;j++){ 13 if(n%(i*j)!=0||i*j==n) continue; 14 aa=min(min(i,j),n/(i*j)); 15 cc=max(max(i,j),n/(i*j)); 16 bb=i+j+n/(i*j)-aa-cc; 17 if(cc-aa<c-a||(cc-aa==c-a&&aa<a)) a=aa,b=bb,c=cc; 18 } 19 if(a==0) printf("No solution\n"); 20 else printf("%d=%d*%d*%d\n",n,a,b,c); 21 } 22 return 0; 23 }
K.梅森素数,3 7 31 127 8191,就这样吧。
L.双流机场。思维题,一开始看错题意了,以为左上角能到其他地方即可,错了一发。然后仔细一看题意是任意两点可达,那就简单了。处于中间的点肯定会有能到达它并且从它出去的路线,所以我们只需要判读四个角不是没有进入的路线,或者没有出去的路线即可。
1 #include<cstdio> 2 const int N=1e5+11; 3 char a[N],b[N]; 4 int main(){ 5 int t,n,m; 6 scanf("%d",&t); 7 while(t--){ 8 scanf("%d%d",&n,&m); 9 scanf("%s%s",a+1,b+1); 10 if(a[1]!=b[1]) printf("Sad\n"); 11 else if(a[1]==b[m]) printf("Sad\n"); 12 else if(a[n]==b[1]) printf("Sad\n"); 13 else if(a[n]!=b[m]) printf("Sad\n"); 14 else printf("Happy\n"); 15 } 16 return 0; 17 }
M.lglg说要有题,于是便有了题。额,打表题,垃圾精度,怪恶心的,根据题目打表来观察即可,但精度很恶心恶心恶心。就小于3输出0,小于29输出1,小于11789输出2,其他输出3。