P13714 淘汰(Hard ver.)
P13714 淘汰(Hard ver.)
题意
略。
思路
参考第一篇题解。
先想了一些最短路的东西,但是复杂度好像怎么都不行。
于是考虑 DP。
对于任意一位,在某一个操作(称为这一位的关键操作)之后,这一位就不再变化。
对于任意一位,在它的关键操作之前,这一位是什么不重要。因为我们的操作一定是霸道地把这一位设为 0/1。
设 \(f_S\) 表示集合为 \(S\) 的位已经固定。那么集合 \(S\) 的位置,与 \(y\) 相同。不属于集合 \(S\) 的位置,随便。
转移。枚举 \(S\) 的补集/的子集 \(T\),钦定这次操作将要固定集合 \(T\) 的位置。
对于 AND 操作为例,要求 \(y\) 在 \(T\) 的位置,均为 \(0\)。可选的 AND 操作,需要满足在 \(T\) 的位置均为 \(0\),且在 \(S\) 中为 \(1\) 的位置,均为 \(1\)。即在 \(T\) 和 (\(S\) 中为 \(1\)) 的位置上,要与 \(y\) 相同。
对于 OR 操作是类似的。
我们预处理出 \(g_S\),表示在集合 \(S\) 上与 \(y\) 相同的 AND 操作,的最小费用。这个可以高位前缀和求。而且因为是取 \(\min\) 操作,所以不用容斥。
对于 OR 操作是类似的。
时间复杂度 \(O(2^k k + 3^k)\)。
code
为了方便写代码,代码中状态定义如下:
- \(f_S\) 表示集合为 \(S\) 的位置还没有固定,不属于集合 \(S\) 的位置已经固定,且与 \(y\) 相同,的最小花费。
- \(ga_S\) 表示集合为 \(S\) 的位置可以与 \(y\) 不相等,不属于集合 \(S\) 的位置一定与 \(y\) 相等,的 AND 操作,的最小花费。
- \(gb_S\) 为 OR 操作,其他同上。
#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace wing_heart {
constexpr int K=16,N=(1<<K)+7;
constexpr ll infll=0x3f3f3f3f3f3f3f3f;
void _min(ll &a,ll b) { a=min(a,b); }
int T;
struct pii {
int w,x;
}a[N],b[N];
int n;
int k;
int s,t;
ll f[N],ga[N],gb[N]; // S 尚未确定(其他=t),S 可以与 y 不相等(and),同前(or)
void main() {
sf("%d",&T);
while(T--) {
sf("%d%d%d%d",&n,&k,&s,&t);
int x;
rep(i,1,n) sf("%d",&x), a[i].x=x;
rep(i,1,n) sf("%d",&x), b[i].x=x;
rep(i,1,n) sf("%d",&x), a[i].w=x;
rep(i,1,n) sf("%d",&x), b[i].w=x;
memset(ga,0x3f,sizeof(ll)<<k);
memset(gb,0x3f,sizeof(ll)<<k);
rep(i,1,n) _min(ga[a[i].x^t],a[i].w);
rep(i,1,n) _min(gb[b[i].x^t],b[i].w);
rep(i,0,(1<<k)-1) {
rep(j,0,k-1) if(!((i>>j)&1)) {
_min(ga[i|(1<<j)],ga[i]);
_min(gb[i|(1<<j)],gb[i]);
}
}
memset(f,0x3f,sizeof(ll)<<k);
int p = s^t;
rep(i,p,(1<<k)-1) if((i|p) == i) f[i]=0;
per(i,(1<<k)-1,0) if(f[i]!=infll) {
for(int j=i;j;j=(j-1)&i) { // 确定 j
if(!(t&j)) _min(f[i^j],f[i]+ga[(((~i)&(~t))|(i^j))&((1<<k)-1)]);
if((t&j)==j) _min(f[i^j],f[i]+gb[((~i)&t)|(i^j)]);
}
}
if(f[0]==infll) puts("-1");
else pf("%lld\n",f[0]);
}
}
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("my.out","w",stdout);
#endif
wing_heart :: main();
}
本文来自博客园,作者:wing_heart,转载请注明原文链接:https://www.cnblogs.com/wingheart/p/19219676

浙公网安备 33010602011771号