3 4 3 2 2 3 2 1 3 2 1 2 3 2 3 1 3 2 2 3 2 3 1 3 1 2 3 0 0 0
3 -3HintFor the first case, in turn 2, bob has to choose at least one bag, so that Alice will make a Magic Stone at the end of turn 3, thus get turn 4 and get all the three Magic Stones.
A和B一起玩游戏。这儿有B个袋子。每个袋子里装有一定量的宝石。有G种颜色的宝石。游戏规则是。A和B轮流从袋子中选一袋宝石。然后将它们倒到公共的容器中。若颜色相同的宝石的个数大于等于S那么每S个石头形成一颗魔法石。并且获得再拿一次的机会。规则同上。每一次获得魔法石的个数即为该次的得分。然后问A和B都采用最优的策略(都使自己得分最多)。A的分数和B的得分的差值。
思路:
由于A和B都足够聪明。那么他们面对相同的局面应该会做出相同的处理。关键在于怎么确定局面。其实我们不用考虑公共容器里的石头的颜色和个数。因为一旦你知道已经有哪些袋子的石头被倒进去了。那么容器里的石头状态也就唯一确定了。因为能形成魔法石的已经都形成了,剩下的当然是不能形成的了。由于A和B都足够聪明那么他们就可以等同了。dp[s]表示。面对局面s时所能得到的最大分数。s为袋子的状态。由于袋子最多21袋所以直接2进制压缩状态就行了。但是由局面s可以转移到那些状态必须还是要知道公共容器里的状态这样才能确定得分情况。S小于20。所以每种颜色宝石的个数可以用5个2进制位压缩。一个__int64就能存下了。这样记忆化DP就行了。
详细见代码:
#include<algorithm> #include<iostream> #include<string.h> #include<sstream> #include<stdio.h> #include<math.h> #include<vector> #include<string> #include<queue> #include<set> #include<map> using namespace std; const int INF=0x3f3f3f3f; const double eps=1e-8; const double PI=acos(-1.0); const int maxn=100010; typedef __int64 ll; //#progma comment(linker,"/STACK:1024000000,1024000000") int g,b,s; int ba[25][10];//存每袋宝石对应颜色的个数 int dp[1<<21|1]; long long op=(1<<5)-1; int sa[25],tail; int dfs(int bag,long long nst,int mp)//bag为袋子的使用情况。nst为公共容器里的宝石状态 { int p,pos,t,st,ans=-1,tans; long long ns,tt; if(dp[bag]!=-1) return dp[bag]; for(p=0;p<b;p++) { t=1<<p;//枚举选择的袋子号 if(t&bag) { tt=nst; tans=ns=0; pos=1;//pos为颜色号 tail=0; while(pos<=g)//注意这里需取出每一种颜色的个数 { st=tt&op; tans+=(st+ba[p][pos])/s; st=(st+ba[p][pos])%s; sa[tail++]=st; tt>>=5; pos++; } while(tail>0)//生成新状态 { ns<<=5; ns|=sa[tail-1]; tail--; } if(tans>=1) tans+=dfs(bag-t,ns,mp-tans);//mp为剩下宝石能得的最大分 else tans=mp-dfs(bag-t,ns,mp-tans);//剩下最大分减下个人的最大得分就为自己的得分了 ans=max(ans,tans); } } return dp[bag]=ans; } int main() { int i,j,n,c,mp,ans,t; //freopen("in.txt","r",stdin); while(scanf("%d%d%d",&g,&b,&s),b||g||s) { memset(ba,0,sizeof ba); memset(dp,-1,sizeof dp); dp[0]=0;//开始傻逼了没初始化。。。 mp=0; for(i=0;i<b;i++) { scanf("%d",&n); while(n--) { scanf("%d",&c); ba[i][c]++; } } for(i=1;i<=g;i++) { t=0; for(j=0;j<b;j++) t+=ba[j][i]; mp+=t/s; } ans=dfs((1<<b)-1,0,mp); ans=2*ans-mp; printf("%d\n",ans); } return 0; }