这就是斐波那契博弈的加强版
对于某些特定的
K
我们有结论
K=1 后手必胜当且仅当 n 是2 的次幂 先手的策略是取 lowbit(n)-
K=2
后手必胜当且仅当
n
是斐波那契数 先手的策略是取
n 的斐波那契拆分中最小的数 这道题 我们仿照斐波那契博弈的构造方法
构造一个数列 an
将每个自然数都表示成 an 中不连续的几项的和 f1+f2+⋯+fn
数列 fn 中 fj+1>K∗fj 即满足题中的k倍关系- 如果该堆石子恰是数列 an 中的一项 后手必胜
- 否则 该堆石子可以表示为 an 中的不连续几项的和 先手必胜 策略是取其中 f1 个石子 后手取走的石子不会超过 f2 个 继续上述策略 后手永远取不完石子
下面程序中 a 即表示这个序列
b 作为辅助数组表示前 i 个的a 能够按规则构造出的最大的数#include<cstdio> #include<cstdlib> #include<algorithm> #define read(x) scanf("%d",&(x)) using namespace std; const int N=5000005; int n,K,a[N],b[N]; int main(){ int T,Case=0; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(T); while (T--){ read(n); read(K); int x=0,y=0; while (a[x]<n){ a[++x]=b[x-1]+1; while (a[y+1]*K<a[x]) y++; if (a[y]*K<a[x]) b[x]=b[y]+a[x]; else b[x]=a[x]; } printf("Case %d: ",++Case); if (n==a[x]) printf("lose\n"); else{ int ans; for (;n;x--) if (n>=a[x]) n-=a[x],ans=a[x]; printf("%d\n",ans); } } return 0; }
-
K=2
后手必胜当且仅当
n
是斐波那契数 先手的策略是取