题解:P13714 淘汰(Hard ver.)
有可能有用的事实:如果初始
容易发现
那么我们尝试把操作的集合覆盖,改成钦定一个子集归位,尝试做一个 dp。
设
考虑这样归位需要满足的条件:
-
这个数在
S' 包含的位置上必须都是 1。 -
考虑已经归位的那些
0 所在的位置S_0 ,这些位置上必须是0 。
设
我们再回顾一下上面的限制,不难发现,我们的限制实际上只和目标状态有关,比如目标状态有一位是
因此
此时我们再做
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf = 1e11;
int n,k,x,y;
int S0,S1;
int a[200005],b[200005],c[200005],d[200005];
int vor[(1<<16)+5],vand[(1<<16)+5];
int dp[(1<<16)+5];
void solve(){
cin >> n >> k >> x >> y;
for(int i = 1;i<=n;i++)cin >> a[i];
for(int i = 1;i<=n;i++)cin >> b[i];
for(int i = 1;i<=n;i++)cin >> c[i];
for(int i = 1;i<=n;i++)cin >> d[i];
for(int i =0 ;i<(1<<k);i++)dp[i] = vor[i] = vand[i] = inf;
for(int i = 1;i<=n;i++){
vand[a[i]] = min(vand[a[i]],c[i]);
vor[b[i]] = min(vor[b[i]],d[i]);
}
S1 = y,S0 = (1<<k)-1-y;
for(int i = 0;i<k;i++){
for(int j = 0;j<(1<<k);j++){
if(y>>i&1){
//限制是选 1,0 加上 1
if(j>>i&1){
vor[j^(1<<i)] = min(vor[j^(1<<i)],vor[j]);
vand[j^(1<<i)] = min(vand[j^(1<<i)],vand[j]);
}
}else{
if(j>>i&1){
vor[j] = min(vor[j^(1<<i)],vor[j]);
vand[j] = min(vand[j^(1<<i)],vand[j]);
}
}
}
}
int S = (1<<k)-1-(x^y);
dp[S] = 0;
for(int i = 0;i<(1<<k);i++)if((i&S) == i)dp[i] = 0;
for(int i = 0;i<(1<<k);i++){
if(dp[i] == inf)continue;
int s0 = S0&i,s1 = S1&i;
int T1 = S1-s1,T0 = S0-s0;
for(int j = T1;j;j = (j-1)&T1){
dp[i|j] = min(dp[i|j],dp[i]+vor[j|(S0-s0)]);
}
for(int j = T0;j;j = (j-1)&T0){
dp[i|j] = min(dp[i|j],dp[i]+vand[(S0-j)|s1]);
}
}
int res;
if(dp[(1<<k)-1] == inf)res = -1;
else res = dp[(1<<k)-1];
cout << res << '\n';
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
// freopen("P13714_1.in","r",stdin);
int t;cin >> t;
while(t--)solve();
}