hdu1847(求sg)

Good Luck in CET-4 Everybody!
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7720 Accepted Submission(s): 4964

Problem Description
大学英语四级考试就要来临了,你是不是在紧张的复习?也许紧张得连短学期的ACM都没工夫练习了,反正我知道的Kiki和Cici都是如此。当然,作为在考场浸润了十几载的当代大学生,Kiki和Cici更懂得考前的放松,所谓“张弛有道”就是这个意思。这不,Kiki和Cici在每天晚上休息之前都要玩一会儿扑克牌以放松神经。
“升级”?“双扣”?“红五”?还是“斗地主”?
当然都不是!那多俗啊~
作为计算机学院的学生,Kiki和Cici打牌的时候可没忘记专业,她们打牌的规则是这样的:
1、 总共n张牌;
2、 双方轮流抓牌;
3、 每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…)
4、 抓完牌,胜负结果也出来了:最后抓完牌的人为胜者;
假设Kiki和Cici都是足够聪明(其实不用假设,哪有不聪明的学生~),并且每次都是Kiki先抓牌,请问谁能赢呢?
当然,打牌无论谁赢都问题不大,重要的是马上到来的CET-4能有好的状态。

Good luck in CET-4 everybody!

Input
输入数据包含多个测试用例,每个测试用例占一行,包含一个整数n(1<=n<=1000)。

Output
如果Kiki能赢的话,请输出“Kiki”,否则请输出“Cici”,每个实例的输出占一行。

Sample Input

1
3

Sample Output

Kiki
Cici

#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cstring>
#include<cmath>
/* 应该是个巴什博弈吧,首先3是个必败的状态,任何一个不是3的倍数的(>3)都可以经过减1或减2变成3的倍数, 而1和2都是2的倍数,所以如果把对方控制成三的倍数那么必赢,也就是说谁先抢到不是三的倍数谁赢 如果不想证直接自己写几个必胜必败状态就ok了 必赢 1 2 4 5 7 8 10 11 16 32 必输 3 6 9 12 首先,我们可以确定的是,如果谁面对的是3这个局势,那是先者是必败的,后者总可以拿最后一个石子,那3+3呢? 当然也是啦,依次类推,凡是3的倍数,皆是奇异局势 */

//const int maxn=2049;
//int a[maxn];

//int main(){
// int n;
// memset(a,-1,sizeof(a));
// for(int i=0;pow(2,i)<=1000;++i){
// a[(int)pow(2,i)]=1;
// }
// for(int i=1;i<=1000;++i){
// if(a[i]!=-1)continue;
// bool ans=false;
// for(int j=0;pow(2,j)<=1000;++j){
// if(i-(int)(pow(2,j))>0){
// if(!a[i-(int)(pow(2,j))]){
// ans=true;
// break;
// }
// }
// }
// a[i]=ans;
// }
// while(cin>>n){
//// if(n%3)printf("Kiki\n");
//// else printf("Cici\n");
// //求 SG 值
// if(a[n])printf("Kiki\n");
// else printf("Cici\n");
// }
// return 0;
//}
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;


const int maxn = 1000 + 10;
int arr[11], sg[maxn];


void pre() { //把1000以内的所有的可能一次拿的牌都算出来!
    arr[0] = 1;
    for(int i=1; i<=10; ++i)
        arr[i] = arr[i-1]*2;
}

/* SG值:一个点的SG值就是一个不等于它的后继点的SG的且大于等于零的最小整数。//同mex()函数 简单点来讲就是当前状态离最近一个必败点的距离。距离为0就是必败点 SG(x)=mex(S) S是x的后继状态的SG函数值集合 mex(S)表示不在S内的最小非负整数 */
int mex(int x) { //这是求解该点的sg值的算法函数(采用记忆化搜索)
    if(sg[x]!=-1) return sg[x];
    bool vis[maxn];
    memset(vis, false, sizeof(vis) );
    for(int i=0; i<10; ++i) {
        int temp = x - arr[i];
        if(temp<0) break;
        sg[temp] = mex(temp);
        vis[sg[temp]] = true;
    }

    for(int i=0;i<=1000; ++i) {
        if(!vis[i]) {
            sg[x] = i;
            break;
        }
    }
    return sg[x];
}
int main() {
    int n;
    pre();
    memset(sg, -1, sizeof sg );
    while(scanf("%d", &n)!=EOF) {

        if(mex(n)) printf("Kiki\n");
        else printf("Cici\n");
    }
    return 0;
}

你可能感兴趣的:(hdu1847(求sg))