两场比赛:
比赛:第八届福建省大学生程序设计竞赛-重现赛
队伍出题:7/12
个人出题:4
越来越感受到了团队配合的好处。
D:Alice和Bob玩游戏,每个人有一个字符串,每回合每个人有两种操作(Alice先手):1、把自己的字符串倒过来2、把自己的字符串的最后一个字符舍去。若两个人的字符串相同则Alice胜,否则Bob胜。
分情况讨论:
1、最关键的一点,Bob的串为0则Alice一定获胜。(这是关键)
2、Bob的串长度大于Alice的长度,则肯定Bob获胜
3、否则,如果Bob的串是Alice的子串或者是Alice的逆串的子串,则Alice获胜,否则Bob获胜。这里用kmp即可。
只要想到了第一点,AC即很简单了。
代码:
#include<iostream> #include<cmath> #include<string> #include<string.h> #include<algorithm> #include<queue> #include<vector> #include<cstdio> #include<map> using namespace std; const int mx=100100; int n,m,ans,T,k; char s[mx],s2[mx],s1[mx],s3[mx]; int f[mx]; void getFail()//i 1 kaishi { f[0]=f[1]=0; for(int i=1;i<m;i++) { int j=f[i]; while(j&&s2[i]!=s2[j]) j=f[j]; f[i+1]=(s2[i]==s2[j])?j+1:0; } } int find(int x,int y) { int j=0; for(int i=0;i<x;i++) { if(j&&s[i]!=s2[j]) j=f[j]; if(s[i]==s2[j]) j++; if(j==y) return 1; } return 0; } int main() { while(scanf("%d",&T)!=EOF) { while(T--) { bool flag=0; scanf("%s",s); scanf("%s",s2); n=strlen(s); m=strlen(s2); for(int i=0;i<n;i++) s3[i]=s[n-i-1]; int a; if(m==1&&s2[0]=='0') puts("Alice"); else if(m>n) puts("Bob"); else { flag=0; getFail(); if(find(n,m))flag=1; for(int i=0;i<n;i++) s[i]=s3[i]; s[n]='\0'; getFail(); if(find(n,m))flag=1; if(flag) puts("Alice"); else puts("Bob"); } } } return 0; }
I题:这题我看了现场赛的榜单没几个过得,但是其实暴力就可以刚好卡过。。。这里就不详细介绍了。所以什么方法都没有的时候,不妨试一下暴力。
K题:n个人随机互相交换礼物,求至少k个人拿到自己的礼物的方法总数。
直接求sum(C(n,i)*yu[n-i]),(k<=i<=n)mod就可以了。这里yu[i]为1到i的错排方法总数。所以都预处理一下就好了。
代码:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #define ll long long using namespace std; const int maxn=100010; const ll mo=1e9+7; int aa[maxn],c[maxn],n,m,k; int cnt,tmp,ans,flag; char s[maxn]; ll dp[10010][110]; ll pl[10010]; ll yu[10010]; int q,x,f,y,p; long long ni[maxn]; long long a[maxn]; long long zuhe(int x,int y){ //组合数 return a[x]*ni[y]%mo*ni[x-y]%mo; } long long calc(long long x,long long y){ long long z=1; while (y){ if (y&1)(z*=x)%=mo; (x*=x)%=mo,y/=2; } return z; } void init() { a[0]=1; for (int i=1;i<maxn;i++)a[i]=a[i-1]*i%mo; ni[maxn-1]=calc(a[maxn-1],mo-2); for (int i=maxn-2;i>=0;i--)ni[i]=ni[i+1]*(i+1)%mo; } int main() { init(); yu[0]=1; yu[1]=0; yu[2]=1; for(int i=3;i<=10000;i++) { yu[i]=((i-1)*(yu[i-1]+yu[i-2])%mo)%mo; } int T; pl[1]=1; for(int i=2;i<=10000;i++) pl[i]=(pl[i-1]*i)%mo; //scanf("%d",&T); while(scanf("%d",&T)!=EOF) { while(T--){ scanf("%d %d",&n,&k); ll ans=0; flag=0; for(int i=k;i<=n;i++){ ans=(ans+(zuhe(n,i)*yu[n-i])%mo)%mo; } printf("%lld\n",ans); } //if(flag) puts("Yes");else puts("No"); } return 0; }
L:题目是给你一个三子棋的棋盘,已经下了若干步,接下来该kim下了,问你他能不能在两步以内获胜。
这道题貌似封榜前只有我们队没过???
题意读的很迷,代码写的更迷,蜜汁WA了7次。
其实只需要判一下:是否现在已经赢了else 是否再下一步就赢了 else 是否再下一步肯定输了 else 是否再下一步就有两种以上的方法取胜。这是个关键,判了这个就不需要再讨论其他情况了。
代码:
#include<iostream> #include<cmath> #include<string> #include<string.h> #include<algorithm> #include<queue> #include<vector> #include<cstdio> #include<map> using namespace std; const int maxn=110; int n,m,ans,T,k,x; char s[maxn][maxn]; char ch,chh; bool jud(char ch) { if(s[0][0]==ch&&s[0][1]==ch&&s[0][2]==ch) return 1; if(s[1][0]==ch&&s[1][1]==ch&&s[1][2]==ch) return 1; if(s[2][0]==ch&&s[2][1]==ch&&s[2][2]==ch) return 1; if(s[0][0]==ch&&s[1][0]==ch&&s[2][0]==ch) return 1; if(s[0][1]==ch&&s[1][1]==ch&&s[2][1]==ch) return 1; if(s[0][2]==ch&&s[1][2]==ch&&s[2][2]==ch) return 1; if(s[0][0]==ch&&s[1][1]==ch&&s[2][2]==ch) return 1; if(s[0][2]==ch&&s[1][1]==ch&&s[2][0]==ch) return 1; return 0; } bool solve() { for(int i=0;i<3;i++) for(int j=0;j<3;j++) if(s[i][j]=='.'){ s[i][j]=chh; x--; if(jud(chh)||x==0) return 0; x++; s[i][j]='.'; } int ans=0; for(int i=0;i<3;i++) for(int j=0;j<3;j++) if(s[i][j]=='.'){ s[i][j]=ch; if(jud(ch)) ans++; s[i][j]='.'; } if(ans>=2) return 1; return 0; } int main() { while(cin>>T) { while(T--) { x=0; bool flag=0; for(int i=0;i<3;i++) for(int j=0;j<3;j++) { cin>>s[i][j]; if(s[i][j]=='.') x++; } //cout<<x<<"*"; cin>>ch; if(ch=='o') chh='x'; else chh='o'; if(jud(ch)) flag=1; else if(jud(chh)||x==0) flag=0; else { for(int i=0;i<3;i++) {for(int j=0;j<3;j++) if(s[i][j]=='.') { s[i][j]=ch; x--; if(jud(ch)) {flag=1;break;} s[i][j]='.'; x++; } if(flag) break; } if(!flag){ for(int i=0;i<3;i++) {for(int j=0;j<3;j++) if(s[i][j]=='.') { s[i][j]=ch; x--; if(x&&solve()){flag=1;break;} s[i][j]='.'; x++; } if(flag) break; } } } if(flag) puts("Kim win!"); else puts("Cannot win!"); } } return 0; }
先写这么多,为了防止博客被吞,今天的北师大校赛重现赛将会重新写一个博客。