QOJ7602 AtCoder Quality Problem
设 \(black[i]\) 为 \(i\) 这个集合内全选黑色的权值和, \(white[i]\) 同理。
考虑一个性质: \(S\) 中一定存在一个元素 \(x\) ,使得所有包含 \(x\) 的子集都是白色的。证明很简单,如果不存在这样一个元素,那么所有黑色子集的并一定会得到 \(S\) ,矛盾。
所以可以枚举 \(x\) ,计算包含 \(x\) 的集合的贡献之后把 \(x\) 删去,可以发现也是一个子问题。故有
\[dp[S] = \min_{x \in S} \{ dp[S-x] + \max \{ black[S]-black[S-x],white[S]-white[S-x] \} \}
\]
枚举子集 \(O(2^n)\) ,枚举子集元素 \(O(n)\) ,总复杂度 \(O(n2^n)\) 。
\(\huge \mathscr{Code}\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1<<21,INF = 1e18;
int n,m,black[N],white[N],dp[N],siz;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n;
siz = 1<<n;
for(int i=0;i<siz;i++) cin>>black[i];
for(int i=0;i<siz;i++) cin>>white[i];
for(int i=0;i<n;i++){
for(int j=0;j<siz;j++){
if((j>>i)&1){
black[j] += black[j^(1<<i)];
white[j] += white[j^(1<<i)];
}
}
}
dp[0] = min(black[0],white[0]);
for(int i=1;i<siz;i++){
dp[i] = INF;
for(int j=0;j<n;j++){
if((i>>j)&1){
dp[i] = min(dp[i],dp[i^(1<<j)] + black[i] - black[i^(1<<j)]);
dp[i] = min(dp[i],dp[i^(1<<j)] + white[i] - white[i^(1<<j)]);
}
}
}
cout<<dp[siz-1];
return 0;
}

浙公网安备 33010602011771号