题解:CF2043F Nim
__vector__ · · 题解
本题披着博弈论的外衣,实际上,除了第一步用 Nim 定理转化题意以外,跟博弈论没什么关系。
题意
给定一个长度为
给定
不能删完,同时求出能使删除数字数量最多的方案数量。
两个方案不同当且仅当删除的位置的集合不同。
无解输出
做法
注意到值域是
对于每一种数字,其最多保留
随后 dp,
状态转移的话,只需要对于每种数字,枚举其保留了几个,转移是显然的。
这是我的 dp 转移的代码:
int rem[51];// 每种数字出现的次数
int top;// 有多少不同的数字
dp[0][0][0]=0;// 最多删多少个
ways[0][0][0]=1; // 保证删最多个的方案数
auto ckmxdp=[&](int nxti,int nxtj,int nxtk,int i,int j,int k,int add,ll waymult)->void{
// nxti,nxtj,nxtk 代表新的状态,i,j,k 是旧的状态,add 是旧的状态转移后 dp 值加上多少,waymult 是本次选保留的位置的方案数。
if(dp[nxti][nxtj][nxtk]<dp[i][j][k]+add){
dp[nxti][nxtj][nxtk]=dp[i][j][k]+add;
ways[nxti][nxtj][nxtk]=ways[i][j][k]*waymult;
}else if(dp[nxti][nxtj][nxtk]==dp[i][j][k]+add){
ways[nxti][nxtj][nxtk]+=ways[i][j][k]*waymult;
}
ways[nxti][nxtj][nxtk]%=mod;
};
for(int i=0;i<top;i++){
for(int j=0;j<=63;j++){
for(int k=0;k<=1;k++){
// 当前这个数不对总 xor 造成影响。
// 情况:保留 0 或 2 个。
ckmxdp(i+1,j,k,i,j,k,rem[i+1],1);
if(rem[i+1]>=2){
ckmxdp(i+1,j,1,i,j,k,rem[i+1]-2,((ll)rem[i+1]*(rem[i+1]-1)/2)%mod);
}
// 当前这个数对总 xor 造成影响。
// 情况:保留 1 个.
if(rem[i+1]>=1){
ckmxdp(i+1,j^b[i+1],1,i,j,k,rem[i+1]-1,rem[i+1]);
}
}
}
}
if(dp[top][0][1]>=0){
printf("%d %lld\n",dp[top][0][1],(ways[top][0][1]%mod+mod)%mod);
}else{
puts("-1");
}