- Matrix Equation 高斯消元
大意:给定 01 矩阵 A,C
求满足 A × B = B ⊙ C A\times B=B\odot C A×B=B⊙C 01 矩阵 B 的个数。
× \times × : D i , j = ∑ k = 1 n A i , k B k , j D_{i,j}=\sum_{k=1}^n{A_{i,k}B_{k,j}} Di,j=∑k=1nAi,kBk,j
⊙ \odot ⊙: D i , j = A i , j B i , j D_{i,j}=A_{i,j}B_{i,j} Di,j=Ai,jBi,j
思路:通过观察上述式子我们发现 D i , j D_{i,j} Di,j 叉乘 是 k 在变化,列是不变的,对于B的各个列之间是相互独立的。所以我们可以对 B 的每一列单独拉出来考虑。对于 B 的第 j 列 记为 b
根据式子我们可以列出 :
( A 1 , 1 b 1 + A 1 , 2 b 2 + . . . . . . A 1 , n b n ) m o d 2 = A 1 , j b 1 (A_{1,1}b_1+A_{1,2}b_2+......A_{1,n}bn)\mod2=A_{1,j}b_1 (A1,1b1+A1,2b2+......A1,nbn)mod2=A1,jb1
( A 2 , 1 b 1 + A 2 , 2 b 2 + . . . . . . A 2 , n b n ) m o d 2 = A 2 , j b 2 (A_{2,1}b_1+A_{2,2}b_2+......A_{2,n}bn)\mod2=A_{2,j}b_2 (A2,1b1+A2,2b2+......A2,nbn)mod2=A2,jb2
…
( A n , 1 b 1 + A n , 2 b 2 + . . . . . . A n , n b n ) m o d 2 = A n , j b n (A_{n,1}b_1+A_{n,2}b_2+......A_{n,n}bn)\mod2=A_{n,j}b_n (An,1b1+An,2b2+......An,nbn)mod2=An,jbn
有 mod 2 的存在,所以也就等价于异或线性方程组:
A 1 , 1 b 1 ⊕ A 1 , 2 b 2 ⊕ . . . . . . A 1 , n b n = A 1 , j b 1 A_{1,1}b_1\oplus A_{1,2}b_2\oplus......A_{1,n}bn=A_{1,j}b_1 A1,1b1⊕A1,2b2⊕......A1,nbn=A1,jb1
A 2 , 1 b 1 ⊕ A 2 , 2 b 2 ⊕ . . . . . . A 2 , n b n = A 2 , j b 2 A_{2,1}b_1\oplus A_{2,2}b_2\oplus......A_{2,n}bn=A_{2,j}b_2 A2,1b1⊕A2,2b2⊕......A2,nbn=A2,jb2
…
A n , 1 b 1 ⊕ A n , 2 b 2 ⊕ . . . . . . A n , n b n = A n , j b n A_{n,1}b_1\oplus A_{n,2}b_2\oplus......A_{n,n}bn=A_{n,j}b_n An,1b1⊕An,2b2⊕......An,nbn=An,jbn
继续化简:
( A 1 , 1 ⊕ C 1 , j ) b 1 ⊕ A 1 , 2 b 2 ⊕ . . . . . . A 1 , n b n = 0 (A_{1,1}\oplus C_{1,j})b_1\oplus A_{1,2}b_2\oplus......A_{1,n}bn=0 (A1,1⊕C1,j)b1⊕A1,2b2⊕......A1,nbn=0
A 2 , 1 b 1 ⊕ ( A 2 , 2 ⊕ C 2 , j ) b 2 ⊕ . . . . . . A 2 , n b n = 0 A_{2,1}b_1\oplus (A_{2,2}\oplus C_{2,j})b_2\oplus......A_{2,n}bn=0 A2,1b1⊕(A2,2⊕C2,j)b2⊕......A2,nbn=0
…
A n , 1 b 1 ⊕ A n , 2 b 2 ⊕ . . . . . . ( A n , n ⊕ C n , j ) b n = 0 A_{n,1}b_1\oplus A_{n,2}b_2\oplus......(A_{n,n}\oplus C_{n,j})b_n=0 An,1b1⊕An,2b2⊕......(An,n⊕Cn,j)bn=0
然后用高斯消元求自由元的个数就行了。自由元的个数为 cnt ,该列对最终结果的贡献就是 2 c n t 2^{cnt} 2cnt
乘法原理把每一列乘起来就行了。
代码如下:
#include <bits/stdc++.h>
#define int long long
#define rep(i,bbb,eee) for(int i=bbb;i<=eee;i++)
#define frep(i,bbb,eee) for(int i=bbb;i>=eee;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define cout(xxx) cout<<fixed<<setprecision(xxx)
#define inf 0x3f3f3f3f
#define pb push_back
#define AC signed
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=1010,M=998244353;
int qmi(int a,int b)
{
int res=1;
while(b)
{
if(b&1)res=res*a%M;
a=a*a%M;
b>>=1;
}
return res%M;
}
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
inline void print(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
//____________________________________________//
int n;
int A[N][N],C[N][N],a[N][N];
int gauss()
{
int r,c;
for(r=0,c=0;c<n;c++)
{
int t=-1;
for(int i=r;i<n;i++)
if(a[i][c])t=i;
if(t==-1)continue;
for(int i=c;i<=n;i++)swap(a[t][i],a[r][i]);
for(int i=r+1;i<n;i++)
if(a[i][c])
for(int j=n;j>=c;j--)
a[i][j]^=a[r][j];
r++;
}
return n-r;
}
void solve()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>A[i][j];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cin>>C[i][j];
int ans=1;
for(int j=0;j<n;j++)
{
for(int i=0;i<n;i++)
for(int k=0;k<n;k++)
a[i][k]=A[i][k];
for(int i=0;i<n;i++)a[i][i]^=C[i][j];
int t=gauss();
ans=ans*qmi(2,t)%M;
}
cout<<ans<<"\n";
}
AC main()
{
ios::sync_with_stdio(false);cin.tie(0);
int _=1;
//cin>>_;
while(_--)solve();
return 0;
}
- Tree Constructer 构造+二分图染色
大意:若u的点权为 x ,v 的点权为 y 。 当且仅当 x ∣ y = 2 60 − 1 x|y=2^{60}-1 x∣y=260−1时u,v 之间有条边。点的个数<=100,现给出一个棵树,要求根据树中边的关系构造出一组合法点权。
思路:构造题重点就是就是想到一种简单的构造方式。根据题目,我们要找到是 a-b-c
a ∣ b = b ∣ c = 2 60 − 1 a|b=b|c=2^{60}-1 a∣b=b∣c=260−1 即 a、c 是一列,b是另一列,类似于染色,黑白色交替。
如果我们令点数目较少的一类为白色点的话,白色点的数目最大不超过50。要保证白色点的之间或运算不为 2 60 − 1 2^{60}-1 260−1, 我们可以令白色点最高0,且第 i 号白色点的 第 i 位为0,这样确保白色点之间是合法的,对于黑色点,最高位是1,周围所有的白色点的编号与之对应的位是1。这样黑白之间也是合法的。因为白色点不超过50个,除了最高位的1,其他的是1的位最高是50,那么更高的位必然全部都是0,黑色点之间也是合法的。
代码如下:
#include <bits/stdc++.h>
#define int long long
#define rep(i,bbb,eee) for(int i=bbb;i<=eee;i++)
#define frep(i,bbb,eee) for(int i=bbb;i>=eee;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define cout(xxx) cout<<fixed<<setprecision(xxx)
#define inf 0x3f3f3f3f
#define pb push_back
#define AC signed
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=110,M=998244353;
int qmi(int a,int b)
{
int res=1;
while(b)
{
if(b&1)res=res*a%M;
a=a*a%M;
b>>=1;
}
return res%M;
}
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
inline void print(int x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
//____________________________________________//
int n,ans[N],id[N];
vector<int> g[N],w,b;
void dfs(int u,int fa,int c)
{
if(c)w.pb(u);
else b.pb(u);
for(auto v:g[u])
{
if(v==fa)continue;
dfs(v,u,c^1);
}
}
void solve()
{
cin>>n;
rep(i,1,n)id[i]=-1;
rep(i,1,n-1)
{
int x,y;
cin>>x>>y;
g[x].pb(y);
g[y].pb(x);
}
dfs(1,0,0);
if(w.size()>b.size())swap(w,b);
int t=(1LL<<59)-1;
for(int i=0;i<w.size();i++)
{
int u=w[i];
id[u]=i;
ans[u]=t^(1LL<<i);
}
t=1LL<<59;
for(int i=0;i<b.size();i++)
{
int u=b[i];
ans[u]=t;
for(auto v:g[u])
{
if(id[v]!=-1)
{
ans[u]|=(1LL<<id[v]);
}
}
}
rep(i,1,n)cout<<ans[i]<<" ";
}
AC main()
{
ios::sync_with_stdio(false);cin.tie(0);
int _=1;
//cin>>_;
while(_--)solve();
return 0;
}