您的位置:首页 > 其它

sgu153 Playing with matches (博弈dp)#by nobody

2013-03-02 16:26 369 查看
 http://acm.sgu.ru/problem.php?contest=0&problem=153 题意:有N根火柴,m个数p1,p2,p3,..pm(m<=8,pi<=9),每个人可以轮流取1根或者pi根火柴,问先取的还是后取的有必胜策略。解析:这个题有点类似与取石子游戏,我们不记f为n根火柴时先取的是否有必胜策略(1或0).那么f[i]是只与f[i-1], f[i-p[1]], f[i-p[2]], ... f[i-p[m]]有关的,如果这些状态都是赢,那么f[i]就是输,否则f[i]是赢.但是n太大了10^9。注意到pi最大只有9,那么pi必定是由i前9之内的某个或某些状态推出来的,由于九个状态的组合只有2^9 = 512 种,如果找到2个相等的话就找到了周期,那么f必存在一个小于512的周期。所以问题转化为了找f的周期,求值.code
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int main(){//freopen("input.txt","r",stdin);int k;scanf("%d",&k);int p[100];int f[512];int pos[512];while(k--){memset(pos,0,sizeof(pos));int m,n;scanf("%d%d",&n,&m);for(int i=0;i<m;i++)scanf("%d",&p[i]);p[m++] = 1;sort(p,p+m);int t = 0;for(int i=0;i<m;i++)if(p[i]!=p[i+1] || i == m-1)p[t++] = p[i];m = t;f[1] = 0;int l2 = 2,l1 = -1;int x = 0;while(l1 == -1){f[l2] = 1;for(int i=0;i<m && l2-p[i] > 0 && f[l2];i++) f[l2] &= f[l2-p[i]];f[l2] = !f[l2];if(pos[x]) l1 = pos[x];else{pos[x] = l2;x = (x<<1) & 0x1ff | f[l2];l2++;}}int ans;if(n<=l1) ans = f;else ans = f[(n-l1)%(l2-l1)+l1];if(ans)printf("FIRST PLAYER MUST WIN\n");else printf("SECOND PLAYER MUST WIN\n");}return 0;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: