好题,首先观察可得w[i][j]选择只有可能两种,一种比阀值大,一种比阀值小
比阀值大就一定选满足条件最大的w,比阀值小同样一定选满足条件最大的w
那么一个最小割模型就呼之欲出了,注意w可能是负数那么就集体+1025;
我们把这两种情况分辨记作w[i][mx[i]],w[i][mi[i]]
下面是建图,观察两个byte产生收益是or条件似乎不好处理
但仔细观察连边条件可以发现,二进制只有1位不同意味着byte编号一定可以构成一个二分图
于是,对于二进制所含1的个数为奇数的i,连边(s,i,w[i][mi[i]]),(i,t,w[i][mx[i]]),而对二进制所含1的个数为偶数的数j则相反
额外收益即可表示为(i,j,u[i]^u[j])
那么最大分数=总分数-最小割-n*1025;
下面就是构造方案了,我一开始sb wa了很久
首先有的w[i]中不存在比阀值小的情况,那这些byte分配什么value是确定的
做完最小割后,我们从s沿残流网络做一遍dfs,如果s可以走到i,就意味着(s,i)的边可以不割,(i,t)的边要割
那么对应点如何选择也就出来了

1 #include<bits/stdc++.h> 2 3 using namespace std; 4 struct way{int flow,po,next;} e[600010]; 5 int p[610],numh[610],h[610],cur[610],pre[610],d[610],cl[610],w[610][610],mx[610],mi[610],ans[610],u[610],b[610]; 6 bool v[610]; 7 int n,m,ln,lm,len,t; 8 const int lim=1025; 9 const int inf=1000000007; 10 11 void add(int x,int y,int f) 12 { 13 e[++len].po=y; 14 e[len].flow=f; 15 e[len].next=p[x]; 16 p[x]=len; 17 } 18 void build(int x, int y, int f) 19 { 20 add(x,y,f); 21 add(y,x,0); 22 } 23 24 int sap() 25 { 26 memset(h,0,sizeof(h)); 27 memset(numh,0,sizeof(numh)); 28 numh[0]=t+1; 29 for (int i=0; i<=t; i++) cur[i]=p[i]; 30 int j,u=0,s=0,neck=inf; 31 while (h[0]<t+1) 32 { 33 d[u]=neck; 34 bool ch=1; 35 for (int i=cur[u]; i!=-1; i=e[i].next) 36 { 37 j=e[i].po; 38 if (e[i].flow>0&&h[u]==h[j]+1) 39 { 40 neck=min(neck,e[i].flow); 41 cur[u]=i; 42 pre[j]=u; u=j; 43 if (u==t) 44 { 45 s+=neck; 46 while (u) 47 { 48 u=pre[u]; 49 j=cur[u]; 50 e[j].flow-=neck; 51 e[j^1].flow+=neck; 52 } 53 neck=inf; 54 } 55 ch=0; 56 break; 57 } 58 } 59 if (ch) 60 { 61 if (--numh[h[u]]==0) return s; 62 int q=-1,tmp=t; 63 for (int i=p[u]; i!=-1; i=e[i].next) 64 { 65 j=e[i].po; 66 if (e[i].flow&&h[j]<tmp) 67 { 68 tmp=h[j]; 69 q=i; 70 } 71 } 72 cur[u]=q; h[u]=tmp+1; 73 numh[h[u]]++; 74 if (u) 75 { 76 u=pre[u]; 77 neck=d[u]; 78 } 79 } 80 } 81 return s; 82 } 83 84 bool dfs(int x) 85 { 86 v[x]=1; 87 for (int i=p[x]; i>-1; i=e[i].next) 88 { 89 int y=e[i].po; 90 if (!e[i].flow) continue; 91 if (!v[y]) dfs(y); 92 } 93 } 94 95 int main() 96 { 97 int cas; 98 scanf("%d",&cas); 99 for (int i=0; i<256; i++) 100 { 101 for (int j=0; j<8 ;j++) 102 cl[i]^=(i>>j)&1; 103 } 104 while (cas--) 105 { 106 scanf("%d%d",&ln,&lm); 107 n=1<<ln; m=1<<lm; 108 len=-1; memset(p,255,sizeof(p)); 109 memset(ans,0,sizeof(ans)); 110 for (int i=1; i<=n; i++) scanf("%d",&b[i]); 111 for (int i=1; i<=n; i++) scanf("%d",&u[i]); 112 for (int i=1; i<=n; i++) 113 { 114 mi[i]=mx[i]=0; 115 w[i][0]=-lim; b[i]++; 116 for (int j=1; j<b[i]; j++) 117 { 118 scanf("%d",&w[i][j]); 119 if (w[i][mi[i]]<w[i][j]) mi[i]=j; 120 } 121 for (int j=b[i]; j<=m; j++) 122 { 123 scanf("%d",&w[i][j]); 124 if (w[i][mx[i]]<w[i][j]) mx[i]=j; 125 } 126 if (!mi[i]) ans[i]=mx[i]; 127 } 128 t=n+1; 129 for (int i=0; i<n; i++) 130 if (cl[i]) 131 { 132 for (int j=0; j<ln; j++) 133 { 134 int y=i^(1<<j); 135 build(i+1,y+1,u[i+1]^u[y+1]); 136 } 137 } 138 for (int i=1; i<=n; i++) 139 if (cl[i-1]) 140 { 141 build(0,i,w[i][mi[i]]+lim); 142 build(i,t,w[i][mx[i]]+lim); 143 } 144 else { 145 build(0,i,w[i][mx[i]]+lim); 146 build(i,t,w[i][mi[i]]+lim); 147 } 148 sap(); 149 memset(v,0,sizeof(v)); 150 dfs(0); 151 for (int i=p[0]; i>-1; i=e[i].next) 152 { 153 int x=e[i].po; 154 if (ans[x]) continue; 155 if ((v[x]&&cl[x-1])||(!v[x]&&!cl[x-1])) ans[x]=mi[x]; 156 else ans[x]=mx[x]; 157 } 158 for (int i=1; i<=n; i++) 159 { 160 printf("%d",ans[i]-1); 161 if (i!=n) printf(" "); else puts(""); 162 } 163 } 164 }