【博弈论】SRM701PartisanGame
来源:互联网 发布:矩阵双竖线 编辑:程序博客网 时间:2024/06/15 20:41
题意:有n个石子,Alice和Bob依次拿石子,到一方不能再拿即为失败。Alice能够拿的个数有x种,分别是a0,a1..ax。Bob能够拿的个数有y种,分别是b0,b1..bx。Alice先手
1<=n<=1000000000
x<=5,y<=5且1<=ai,bi<=5,ai之间互不相同,bi之间也互不相同
题解:
这道题很不同寻常的是,两者拿的个数种类不一定相同,这也意味着不能单纯地用一维的dp来实现。考虑加维度,显然,我们的目的是区分开当前到底是谁拿,所以第二维为0/1分别表示当前轮到Alice或Bob出手。时间复杂度O(n),但很显然这样并不能过这道题。
所以我们考虑周期性
“x,y<=5且ai,bi<=5”很显然就是突破口,一种情况d[i][x]的答案只会从前5个(d[i-5][!x]–d[i-1][!x])的情况得到。那么不难发现对一种情况有影响的只是前5个情况,所以就可以用前5个的情况来储存当前状态。状态相同即一定为一个周期,用一个十位二进制数来存储,所以不同的状态总数为2^10个,这样就可以把循环的次数降到2^10以下。(详见代码)
#include<cstdio>#include<cstring>#include<algorithm>#include<climits>#define SF scanf#define PF printf#define MAXS 10#define MAXN 1000000using namespace std;int a[MAXS],b[MAXS],d[MAXN][2],was[(1<<(11))+10],n,x,y;int main(){ memset(was,-1,sizeof was); SF("%d",&n); SF("%d",&x); for(int i=1;i<=x;i++) SF("%d",&a[i]); SF("%d",&y); for(int i=1;i<=y;i++) SF("%d",&b[i]); sort(a+1,a+x+1); sort(b+1,b+y+1); for(int i=1;i<=n;i++){ for(int j=1;j<=x&&i-a[j]>=0;j++) if(d[i-a[j]][0]==0){ d[i][1]=1; break; } for(int j=1;j<=y&&i-b[j]>=0;j++) if(d[i-b[j]][1]==0){ d[i][0]=1; break; } if(i>5){ int m=0; for(int j=0;j<5;j++) for(int k=0;k<2;k++){ m*=2; m+=d[i-j][k]; } if(was[m]==-1) was[m]=i; else{ int p=i-was[m]; n-=(n-i)/p*p; } } } if(d[n][1]) PF("Alice"); else PF("Bob");}
0 0
- 【博弈论】SRM701PartisanGame
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 【博弈论】
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- 博弈论
- Button 设置半圆角和阴影
- python
- 使用 Realm 和 Swift 创建 ToDo 应用
- 如何用正确姿势学习获得OpenResty
- 11
- 【博弈论】SRM701PartisanGame
- 基类指针指向派生类对象和隐式转换
- 免费馅饼 [dp]
- sandboxie (沙箱机制)
- 【Android实战】----从Activity入手(编写BaseActivity)
- iOS导入手机通讯录
- tomcat8.5之后版本,远程无法登录管理页面
- 最少拦截系统
- C++关系运算和逻辑运算