Luogu P2447 [SDOI2010]外星千足虫

题意

给定 \(n\) 个变量和 \(m\) 个异或方程,求最少需要多少个才能确定每个变量的解。

\(\texttt{Data Range:}1\leq n\leq 10^3,1\leq m\leq 2\times 10^3\)

题解

高斯消元解异或方程组。

求解这个东西可以直接高斯约旦法,主要问题是第一问。

注意,第一问不等同于求矩阵的秩,因为要求是选一段前缀,矩阵的秩是可以任意选的。

这个时候考虑对选主元过程进行贪心,每一次拿那个位置最前面并且满足条件的当主元来消即可。因为拿靠后的那个方程来消并不能够使答案变得更优,所以贪心策略是正确的。

但是暴力校园是 \(O(n^3)\) 的,感觉跑不过(但是为什么 \(\textsf{t\color{red}ommy0103}\) 就跑过去了),于是可以考虑一下 bitset 优化,这下复杂度就变成了 \(O(\frac{n^3}{\omega})\),实测开 O2 跑得飞快。

代码

#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=1e3+51;
bitset<MAXN>mat[MAXN*2];
ll n,m,pivot,mx;
ll v[MAXN*2],id[MAXN*2];
char ch[MAXN];
inline ll read()
{
    register ll num=0,neg=1;
    register char ch=getchar();
    while(!isdigit(ch)&&ch!='-')
    {
        ch=getchar();
    }
    if(ch=='-')
    {
        neg=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        num=(num<<3)+(num<<1)+(ch-'0');
        ch=getchar();
    }
    return num*neg;
}
int main()
{
    n=read(),m=read(),id[m+1]=m+1;
    for(register int i=1;i<=m;i++)
    {
        scanf("%s",ch+1),v[i]=read(),id[i]=i;
        for(register int j=1;j<=n;j++)
        {
            mat[i][j]=ch[j]-'0';
        }
    }
    for(register int i=1;i<=n;i++)
    {
        pivot=m+1;
        for(register int j=i;j<=m;j++)
        {
            mat[j][i]&&id[pivot]>id[j]?pivot=j:1;
        }
        if(pivot==m+1)
        {
            return puts("Cannot Determine"),0;
        }
        mx=max(mx,id[pivot]),swap(mat[i],mat[pivot]);
        swap(v[i],v[pivot]),swap(id[i],id[pivot]);
        for(register int j=1;j<=m;j++)
        {
            i!=j&&mat[j][i]?mat[j]^=mat[i],v[j]^=v[i]:1;
        }
    }
    printf("%d\n",mx);
    for(register int i=1;i<=n;i++)
    {
        puts(v[i]?"?y7M#":"Earth");
    }
}
posted @ 2020-10-26 10:55  Karry5307  阅读(220)  评论(0编辑  收藏  举报