矩阵

题目描述

你有一个 $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;
}
原文地址:https://www.cnblogs.com/xjqxjq/p/12047264.html