威佐夫博弈 -hdu6869

威佐夫博弈(Wythoff's game):有两堆各若干个物品,两个人轮流从任意一堆中取出至少一个或者同时从两堆中取出同样多的物品,规定每次至少取一个,至多不限,最后取光者胜利。

先找出必败态 (0 0) (1 2) (3 5) (4 7) (6 10) (8 13) (a b)

结论 a=(b-a)*((sqrt(5.0) + 1) / 2)    (sqrt(5.0) + 1) / 2==1.618

 

威佐夫博弈变形:有两堆各若干个物品,两个人轮流从任意一堆中取出至少一个或者同时从两堆中取出分别取出(x,y)的物品|x-y|<=k,规定每次至少取一个,至多不限,最后取光者胜利。

公式:所有的必败态为( floor((1.0-k+sqrt(k*k+2*k+5.0))*n/2.0) , floor((3.0+k+sqrt(k*k+2*k+5.0))*n/2.0) );

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2005;
double k;
ll f(ll n){
    return floor((1.0-k+sqrt(k*k+2*k+5.0))*n/2.0);
}
ll ff(ll n){
    return floor((3.0+k+sqrt(k*k+2*k+5.0))*n/2.0);
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        ll a,b;
        scanf("%lld%lld%lf",&a,&b,&k);
        if(a>b) swap(a,b);
        ll l=1,r=100000000,mid;
        while(l<=r){
            mid=(l+r)/2;
            if(f(mid)>=a) r=mid-1;
            else l=mid+1;
        }
        r++;
        ll l1=1,rr=100000000,mmid;
        while(l1<=rr){
            mmid=(l1+rr)/2;
            if(ff(mmid)>=b) rr=mmid-1;
            else l1=mmid+1;
        }
        rr++;
        if(r==rr&&f(r)==a&&ff(rr)==b) printf("0\n");
        else printf("1\n");
    }
}

 

上一篇:如何用js实现发布了多久的时间描述:几分钟前,几小时前,几天前,几个月前,几年前


下一篇:Mysql 常用函数(21)- floor 函数