您的位置:首页 > 其它

51nod 1661 黑板上的游戏(博弈sg函数找规律)

2016-08-29 13:39 399 查看
1661 黑板上的游戏

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注

Alice和Bob在黑板上玩一个游戏,黑板上写了n个正整数a1, a2, …, an,游戏的规则是这样的:

1. Alice占有先手主动权。

2. 每个人可以选取一个大于1的数字擦去,并写上一个更小的数字,数字必须是整数,然后由对方进行下一次操作。

3. 如果擦去的数字是 x (x > 1) ,则写上的数字不能比 x/k 小,但是要比 x 小。这里的除法为有理数除法。

4. 不可以擦去任何一个数字 1 ,如果当前无法找到一个数字进行操作,则当前方输。

假设Alice和Bob都会选择最优的策略,请问Alice是否存在必胜的方案?

Input

第一行两个空格隔开的正整数n和k,其中n表示数字的个数,k表示游戏的参数。

第二行n个空格隔开的正整数,其中第i个表示ai。

1 ≤ n ≤ 10^5, 2 ≤ k ≤ 10^18, 1 ≤ ai ≤ 10^18。

Output

如果存在必胜方案,则输出“Alice i y”,其中i和y表示先手的一种能必胜的操作:将第i个数修改为y。

如果没有,则输出“Bob”表示后手必胜。

(输出不含引号)

Input示例

4 2

2 3 3 3

Output示例

Alice 2 2

这题一开始感觉无从下手

其实仔细观察之后,可以直接手写sg值找规律

然后发现,sg值是递归的,可以直接求解

这就可以判断胜负了,但是这题还要求输出必胜策略

就枚举每一堆,然后这堆的sg[i],要变为sg[i]异或ans

就是已知sg值,去求最小的这个sg值的状态,然后如果不在范围里

就递归乘k加1上去

方程式a−1−a−1k=sg

不会直接看出来解,只好二分求解,因为有些位置是递归的

但是他们和下一个位置,求出来的sg一样,所以只要二分最小解就行

代码

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
#define   MAX           100005
#define   MAXN          1000005
#define   maxnode       205
#define   sigma_size    2
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   lrt           rt<<1
#define   rrt           rt<<1|1
#define   middle        int m=(r+l)>>1
#define   LL            long long
#define   ull           unsigned long long
#define   mem(x,v)      memset(x,v,sizeof(x))
#define   lowbit(x)     (x&-x)
#define   pii           pair<int,int>
#define   bits(a)       __builtin_popcount(a)
#define   mk            make_pair
#define   limit         10000

//const int    prime = 999983;
const int    INF   = 0x3f3f3f3f;
const LL     INFF  = 0x3f3f;
//const double pi    = acos(-1.0);
const double inf   = 1e18;
//const double eps   = 1e-9;
const LL     mod   = 1e9+7;
const ull    mx    = 133333331;

/*****************************************************/
inline void RI(int &x) {
char c;
while((c=getchar())<'0' || c>'9');
x=c-'0';
while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0';
}
/*****************************************************/

LL x[MAX];
LL b[MAX];
LL k;
LL sg(LL a){
if(a==1) return 0;
if((a-1)%k==0) return sg((a-1)/k);
else{
int tmp=0;
if(a%k!=0) tmp++;
return a-a/k-tmp;
}
}

LL find(LL a,LL y,LL c){
if(a>=y&&a<c) return a;
if((c-1)/k<a) return c;
return find(a*k+1,y,c);
}

LL solve(LL a){
LL l=1,r=1e18;
while(l<=r){
LL mid=(l+r)/2;
LL tmp=mid-1-(mid-1)/k;
if(tmp>=a) r=mid-1;
else l=mid+1;
}
return l;
}
int main(){
//freopen("in.txt","r",stdin);
int n;
cin>>n>>k;
LL ans=0;
for(int i=1;i<=n;i++){
scanf("%I64d",&x[i]);
b[i]=sg(x[i]);
ans^=b[i];
}
if(ans){
printf("Alice");
for(int i=1;i<=n;i++){
if(x[i]==1) continue;
LL tmp=ans^b[i];
tmp=solve(tmp);
tmp=find(tmp,x[i]/k+((x[i]%k==0)?0:1),x[i]);
if(tmp<x[i]){
printf(" %d %I64d\n",i,tmp);
break;
}
}
}
else printf("Bob\n");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: