题目描述
你有一个 $n$ 行 $m$ 列的 $01$ 矩阵 $A$ 。
如果矩阵的第 $i$ 列有奇数个 $1$ ,那么它的权值就是 $a_i imes 3^{b_i}$ ,否则它的权值就是 $0$ 。一个矩阵的权值定义为每列的权值和。
现在你可以删去这个矩阵的任意多行 (可以为 $0$ ),使得矩阵的权值最大。
数据范围
$1 le m le 70$ ; $a_i=±1$ ; $1 le b_i le 35$ ;$b_i e b_j && a_i e a_j$ ; $1 le n le 2 imes 10^5$
题解
考虑每一行为一个二进制数,把问题转化成选中一些串行进行异或,得到的串 $c$ 的价值为 $c_i imes a_i imes 3^{b_i}$ ,使其最大。
考虑按位贪心,用线性基维护异或值,注意考虑 $b_i$ 相同的情况。先看能否只取 $1$ ,否则要使这两位相同,在线性基里加入 $11$ 即可。
代码
#include <bits/stdc++.h> #define LL long long using namespace std; int n,m,f[75],g[75],p[75],h[75]; bool is[75]; LL pw[75]; bitset<75>b,a[75],c; char ch[200005][75]; LL cal(bitset<75> x){ LL s=0; for (int i=0;i<m;i++) if (x[i]) s+=pw[g[p[i]]]*f[p[i]]; return s; } bool cmp(int x,int y){ return g[x]<g[y] || (g[x]==g[y] && f[x]<f[y]); } void ins(){ for (int j=m-1;~j;j--) if (b[j]){ if (is[j]) b^=a[j]; else{a[j]=b;is[j]=1;break;} } } bool check(int x){ return ((b[x]^h[x])^(b[x-1]^h[x-1])); } int main(){ cin>>n>>m;pw[0]=1; for (int i=1;i<=35;i++) pw[i]=3ll*pw[i-1]; for (int i=1;i<=n;i++) scanf("%s",ch[i]); for (int i=0;i<m;i++) scanf("%d%d",&f[i],&g[i]),p[i]=i; sort(p,p+m,cmp); for (int i=1;i<=n;i++){ for (int j=0;j<m;j++) b[j]=(ch[i][p[j]]=='1');ins(); } for (int i=0;i<m;i++) if (f[p[i]]>0) h[i]=1; for (int i=m-1;~i;i--){ if (i && g[p[i]]==g[p[i-1]] && is[i] && !is[i-1]){ b=c; bool f1=check(i); b^=a[i]; bool f2=check(i); if (f1 && f2){ b=a[i];b[i]=b[i-1]=0;ins(); } else if (c[i]^h[i]) c=b; i--;continue; } if (c[i]^h[i]) c^=a[i]; } cout<<cal(c)<<endl; return 0; }