[K倍动态减法问题] HDU 2486 & HDU2580 & POJ3922 a simple stone game

来源:互联网 发布:算法之美 pdf 编辑:程序博客网 时间:2024/04/28 19:25

这就是斐波那契博弈的加强版
对于某些特定的K 我们有结论

  • K=1 后手必胜当且仅当n2的次幂 先手的策略是取lowbit(n)
  • K=2 后手必胜当且仅当n是斐波那契数 先手的策略是取n的斐波那契拆分中最小的数

这道题 我们仿照斐波那契博弈的构造方法
构造一个数列an
将每个自然数都表示成an中不连续的几项的和 f1+f2++fn
数列fnfj+1>Kfj 即满足题中的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;}
0 0