[2020-2021 ACM-ICPC Brazil Subregional Programming Contest] K. Between Us(高斯消元异或方程组)

设在第一个集合中是 0 0 0,在第二个集合中是 1 1 1

u 1 , u 2 . . . u x u_1,u_2...u_x u1,u2...ux u i u_i ui有边

那么和 u i u_i ui相等的节点是奇数个,其他节点都是 u i ⊕ 1 u_i\oplus 1 ui1

那么显然需要分 u i u_i ui朋友的奇偶来分的。

u i u_i ui的朋友是奇数个

那么和 u i u_i ui相等的节点也是奇数个,所以这部分和 u i u_i ui异或是零

而且其他和 u i u_i ui不等的节点间是偶数个,所以异或值为零

所以有 u 1 ⊕ u 2 ⊕ . . . u x ⊕ u i = 0 u_1\oplus u_2\oplus ...u_x\oplus u_i=0 u1u2...uxui=0

u i u_i ui的朋友是偶数个

那么和 u i u_i ui相等的节点是奇数个,这部分和 u i u_i ui异或为零

其他和 u i u_i ui不等的节点也是奇数个,所以奇数个相同的数异或就是自己,也就是 u i ⊕ 1 u_i\oplus 1 ui1

所以有 u 1 ⊕ u 2 ⊕ . . . ⊕ u i = u i ⊕ 1 u_1\oplus u_2\oplus...\oplus u_i=u_i\oplus 1 u1u2...ui=ui1

就是 u 1 ⊕ u 2 ⊕ . . . u x = 1 u_1\oplus u_2\oplus ...u_x=1 u1u2...ux=1

解这个异或方程组即可

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
%:pragma GCC optimize("-fgcse")
%:pragma GCC optimize("-fgcse-lm")
%:pragma GCC optimize("-fipa-sra")
%:pragma GCC optimize("-ftree-pre")
%:pragma GCC optimize("-ftree-vrp")
%:pragma GCC optimize("-fpeephole2")
%:pragma GCC optimize("-ffast-math")
%:pragma GCC optimize("-fsched-spec")
%:pragma GCC optimize("unroll-loops")
%:pragma GCC optimize("-falign-jumps")
%:pragma GCC optimize("-falign-loops")
%:pragma GCC optimize("-falign-labels")
%:pragma GCC optimize("-fdevirtualize")
%:pragma GCC optimize("-fcaller-saves")
%:pragma GCC optimize("-fcrossjumping")
%:pragma GCC optimize("-fthread-jumps")
%:pragma GCC optimize("-funroll-loops")
%:pragma GCC optimize("-fwhole-program")
%:pragma GCC optimize("-freorder-blocks")
%:pragma GCC optimize("-fschedule-insns")
%:pragma GCC optimize("inline-functions")
%:pragma GCC optimize("-ftree-tail-merge")
%:pragma GCC optimize("-fschedule-insns2")
%:pragma GCC optimize("-fstrict-aliasing")
%:pragma GCC optimize("-fstrict-overflow")
%:pragma GCC optimize("-falign-functions")
%:pragma GCC optimize("-fcse-skip-blocks")
%:pragma GCC optimize("-fcse-follow-jumps")
%:pragma GCC optimize("-fsched-interblock")
%:pragma GCC optimize("-fpartial-inlining")
%:pragma GCC optimize("no-stack-protector")
%:pragma GCC optimize("-freorder-functions")
%:pragma GCC optimize("-findirect-inlining")
%:pragma GCC optimize("-fhoist-adjacent-loads")
%:pragma GCC optimize("-frerun-cse-after-loop")
%:pragma GCC optimize("inline-small-functions")
%:pragma GCC optimize("-finline-small-functions")
%:pragma GCC optimize("-ftree-switch-conversion")
%:pragma GCC optimize("-foptimize-sibling-calls")
%:pragma GCC optimize("-fexpensive-optimizations")
%:pragma GCC optimize("-funsafe-loop-optimizations")
%:pragma GCC optimize("inline-functions-called-once")
%:pragma GCC optimize("-fdelete-null-pointer-checks")
const int maxn = 309;
int n,k,a[maxn][maxn],in[maxn],ans[maxn];
int freedom[maxn],num;//存储自由元的位置
int Gauss(int m,int n)
{//m为行数,n为列数(不含常数列)
    int col=0,k=0;//col为列号,k为行号
    for(;k<m&&col<n;k++,col++){
        int r=k;
        for(int i=k+1;i<m;i++){//找系数最大的列
            if(abs(a[i][col])>a[r][col])r=i;
        }
        if(a[r][col]==0){//如果一列都为0就跳过
            freedom[num++]=col;//存储自由元的列数
            k--;continue;
        }
        if(r!=k)for(int i=col;i<=n;i++){//交换行
            swap(a[k][i],a[r][i]);
        }
        for(int i=k+1;i<m;i++){//消元
            if(abs(a[i][col])!=0){
                for(int j=col;j<=n;j++){
                    a[i][j]^=a[k][j];
                }
                //a[i][j]=0;
            }
        }
    }
    for(int i=k;i<m;i++){
        if(a[i][col]!=0)return -1;//无解标志
    }
    if(k<n)return n-k;//如果有自由元,返回自由元个数
    for(int i=n-1;i>=0;i--){
        ans[i]=a[i][n];
        for(int j=i+1;j<n;j++){
            ans[i]^=(a[i][j]&&ans[j]);
        }
    }
    return 0;//有解标志
}
int main()
{
	cin >> n >> k;
	for(int i=1;i<=k;i++)
	{
		int l,r; cin >> l >> r;
		l--,r--;
		in[l]++,in[r]++; a[l][r]=1; a[r][l]=1;
	}
	for(int i=0;i<n;i++)
	{
		if( in[i]%2==0 )	a[i][n] = 1;
		else	a[i][i] = 1;
	}
	if( Gauss(n,n)!=-1 )	cout << "Y";
	else	cout << "N";
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值