威佐夫博弈
普通威佐夫博弈:
两种操作:一、同时在两堆上取相同的个数。二、在某一堆上取任意个数。(每次取不为0)
a [ n ] = n α , b [ n ] = a [ n ] + n , α = 1 + 5 2 a[n] = n \alpha, b[n] = a[n] + n,\alpha = \frac{1 + \sqrt5}{2} a[n]=nα,b[n]=a[n]+n,α=21+5,这个时候是可以确定必败状态的。
这里就不详细展开证明了。
威佐夫博弈拓展:
两种操作:一、同时在两堆分别取 x , y , ∣ x − y ∣ < = k x, y, \mid x - y \mid <= k x,y,∣x−y∣<=k。二、在某一堆上取任意个数。(每次取不为0)
对于给定的限定 k k k,于是题目判定变成了 a [ n ] = n α , b [ n ] = a [ n ] + ( k + 1 ) n a[n] = n \alpha, b[n] = a[n] + (k + 1)n a[n]=nα,b[n]=a[n]+(k+1)n,带入 k k k等于0的时候也就是普通情况下成立,
所以我们可以先解得 α \alpha α,然后再通过二分去寻找是否有符合要求的 n n n,这个时候 α \alpha α的有关方程是 1 α + 1 α + k + 1 = 1 \frac{1}{\alpha} + \frac{1}{\alpha + k + 1} = 1 α1+α+k+11=1。
即可解的方程然后带入验证即可。
取(2堆)石子游戏(普通威佐夫)
/*
Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define endl '\n'
#define mid (l + r >> 1)
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double pi = acos(-1.0);
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;
inline ll read() {
ll f = 1, x = 0;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return f * x;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int a, b;
while(cin >> a >> b && (a + b)) {
map<int, int> MP;
if(a < b) swap(a, b);
int k = (a - b) * ((1 + sqrt(5)) / 2);
if(k == b) {
puts("0");
continue;
}
puts("1");
for(int i = 1; i <= b; i++) {
int n = a - i, m = b - i;
int k = (n - m) * ((1 + sqrt(5)) / 2);
if(k == m) {
printf("%d %d\n", m, n);
}
}
for(int i = 1; i <= a; i++) {
int n = a - i, m = b;
if(n < m) swap(n, m);
int k = (n - m) * ((1 + sqrt(5)) / 2);
if(MP[m] == n) continue;
MP[m] = n;
if(k == m) {
printf("%d %d\n", min(n, m), max(n, m));
}
}
for(int i = 1; i <= b; i++) {
int n = a, m = b - i;
if(n < m) swap(n, m);
int k = (n - m) * ((1 + sqrt(5)) / 2);
if(MP[m] == n) continue;
MP[m] = n;
if(k == m) {
printf("%d %d\n", m, n);
}
}
}
return 0;
}
Slime and Stones(拓展威佐夫)
/*
Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define endl '\n'
#define mid (l + r >> 1)
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double pi = acos(-1.0);
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;
inline ll read() {
ll f = 1, x = 0;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return f * x;
}
ll calc(ll n, ll k) {
double A = 1, B = k - 2, C = -k;
double a = (sqrt(B * B - 4 * A * C) - B) / (2 * A);
ll l = 1, r = 1e9;
while(l < r) {
ll Mid = l + r >> 1;
ll now = Mid * a + k * Mid;
if(now >= n) r = mid;
else l = mid + 1;
}
ll now = l * a + k * l;
return now == n ? l : -1;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T = read();
while(T--) {
ll a = read(), b = read(), k = read() + 1;
if(a < b) swap(a, b);
ll n = calc(a, k);
if(n == -1) puts("1");
else {
if(a - b == n * k) puts("0");
else puts("1");
}
}
return 0;
}