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();
}
posted @ 2025-11-13 22:10  wing_heart  阅读(12)  评论(0)    收藏  举报