杭电多校九 HDU6869 Slime and Stones(扩展威佐夫博弈)

题意:
两堆石子,给一个 k k k
你可以对一堆石子取任意个,也可以对两堆石子取x,y个,保证|x-y|≤k。
先取完获胜,求先手能否获胜。

思路:
建议去看大佬博客
以为是思维题,想了很久,结果是算法题orz。

对于威佐夫博弈,就是题中 k = 0 k=0 k=0的情况
1 a + 1 a + 1 = 1 \frac{1}{a}+\frac{1}{a+1}=1 a1+a+11=1

由此求出 a = 1 + 5 2 a=\frac{1+\sqrt{5}}{2} a=21+5

那么必败态就是
A = a ∗ n , B = A + n A=a*n,B=A+n A=anB=A+n n n n代表是第几项必败态。(具体证明感觉很复杂,可以参考链接)

那么只要先手属于必败态,那么必输,否则就必胜。

本题中多了个 k k k,实际就是变成了
1 a + 1 a + 1 + k = 1 \frac{1}{a}+\frac{1}{a+1+k}=1 a1+a+1+k1=1

k = k + 1 k=k+1 k=k+1
变形成
a 2 + ( k − 2 ) ∗ a − k = 0 a^2+(k-2)*a-k=0 a2+(k2)ak=0

同样可得必败态为 A = a ∗ n , B = A + n ∗ k A=a*n,B=A+n*k A=an,B=A+nk

我们已知 A , B A,B A,B,只需要二分判断是否存在相应的 n n n,使得式子成立即可。
式子成立,说明先手必败,否则必胜。

#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;
const int maxn = 1e5 + 7;

ll a,b,k;

ll get() {
      //寻找是第几项必败态
    ll A = 1,B = k - 2,C = -k;
    ll res = B * B - 4 * A * C;
    ll l = 0,r = 1e8 + 7;
    while(l <= r) {
     
        ll mid = (l + r) / 2;
        ll now = mid * ((-B + sqrt(res)) / 2);
        if(now > a) {
     
            r = mid - 1;
        } else if(now < a) {
     
            l = mid + 1;
        } else {
     
            return mid;
        }
    }
    return -1;
}

int main() {
     
    int T;scanf("%d",&T);
    while(T--) {
     
        scanf("%lld%lld%lld",&a,&b,&k);
        if(a > b) swap(a,b);
        k++;
        ll n = get();
        if(n == -1) printf("1\n");
        else {
     
            if(b - a == n * k) printf("0\n");
            else printf("1\n");
        }
    }
    return 0;
}

你可能感兴趣的:(#,威佐夫博弈,#,其他比赛题目)