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) { // 确定 jif(!(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 LOCALfreopen("in.txt","r",stdin);freopen("my.out","w",stdout);#endifwing_heart :: main();
}