2018年4月28日训练日记(第一场比赛)

两场比赛:

比赛:第八届福建省大学生程序设计竞赛-重现赛

队伍出题: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;
}

先写这么多,为了防止博客被吞,今天的北师大校赛重现赛将会重新写一个博客。

猜你喜欢

转载自blog.csdn.net/lsd20164388/article/details/80138315