杭州区域赛的题目
题意:
B个包,里面有不同数量和颜色的宝石。每轮,Alice或Bob选一个未选过的包,把包里的宝石倒入熔炉中。如果熔炉中同种颜色的>=S个,那么每S个会合成一个魔法石。魔法石给当前操作的人,同时此人可以继续操作一轮。他们都需要获得尽可能多的魔法石,两人操作都最佳,求A-B。
思路:
dp[state] 表示当前操作的人-后手的最大差值 ,state表示选包的情况,1表示可选,0表示已选。
枚举状态,再枚举选包。假设选第i个包,求出此时能获得魔法石的数量,如果大于0说明后手还是自己。
如果后手是自己,那么就+dp[(1<<i)^st]
否则-dp[(1<<i)^st];
code:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
#define N 200010
#define ll long long
#define ALL(x) x.begin(),x.end()
#define CLR(x,a) memset(x,a,sizeof(x))
typedef pair<int,int> PI;
const int INF=0x3fffffff;
const int MOD =1000000007;
const double EPS=1e-7;
int c[32][16];
int dp[1<<21];
int cnt[16],tmp[16];
int G,B,S;
int cal(int st){
for(int i=0;i<B;i++) if(1<<i&st){
for(int j=0;~c[i][j];j++) cnt[c[i][j]]++;
}
int ans=0;
for(int i=0;i<=G;i++) ans+=cnt[i]/S,cnt[i]%=S;
return ans;
}
int main(){
while(~scanf("%d%d%d",&G,&B,&S),G||B||S){
CLR(cnt,0);
for(int i=0;i<B;i++){
int n;
scanf("%d",&n);
for(int j=0;j<n;j++) scanf("%d",&c[i][j]);
c[i][n]=-1;
}
int M=1<<B;
for(int st=1;st<M;st++){
dp[st]=-INF;
CLR(cnt,0);
cal((M-1)^st);
memcpy(tmp,cnt,sizeof(cnt));
for(int i=0;i<B;i++) if(1<<i&st){
memcpy(cnt,tmp,sizeof(cnt));
int bonus=cal(1<<i);
if(bonus) dp[st]=max(dp[st],dp[1<<i^st]+bonus);
else dp[st]=max(dp[st],-dp[1<<i^st]);
}
}
printf("%d\n",dp[M-1]);
}
return 0;
}