【2022国赛模拟】SB的数学研究——线性代数

这个链接是假的

题目描述

在这里插入图片描述
在这里插入图片描述

题解

图论不行,网络流不行,就只能往线性代数方面走。

这里有个十分巧妙的做法,就是用矩阵行列式和多项式循环卷积来刻画两个条件:
构造矩阵 A A A:
a i j = [ f i j ≥ 0 ] c i j x f i j a_{ij}=[f_{ij}\ge 0]c_{ij} x^{f_{ij}} aij=[fij0]cijxfij x x x 是未知数, c i j c_{ij} cij 是每个元素随即分配的一个权值。此时矩阵的每个元素是一个单项式,以循环卷积来做高消的话,求出来的行列式就是一个度数 < k <k <k 的多项式。

这个时候,如果原矩阵不存在完美匹配,那么矩阵的行列式一定为0。否则由于分配了随机权值,每个排列的值不容易抵消掉。如果存在一个排列的合适程度和   m o d   k = i \bmod k=i modk=i,那么行列式的 i i i 次项系数很大概率不为 0。所以我们得到一个较暴力的做法:求出 A A A 的行列式,根据常数项是否为零判断答案。

暴力卷积显然是 O ( n 5 ) O(n^5) O(n5) 的,我们可以考虑先把多项式转换成点值,求出行列式过后再插值回去。由于要做到循环卷积,所以当然想到求单位根的点值。但是直接复数单位根会有精度问题,我们可以考虑找一个大质数 P P P 满足 k ∣ φ ( P ) k|\varphi(P) kφ(P),然后用原根的若干次方代替单位根。这个大质数暴力枚举找一下即可,很快就找到了。

然后就得到 O ( n 4 ) O(n^4) O(n4) 的算法。

代码

#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define lll __int128
#define uns unsigned
#define fi first
#define se second
#define IF (it->fi)
#define IS (it->se)
#define END putchar('\n')
#define lowbit(x) ((x)&-(x))
#define inline jzmyyds
using namespace std;
const int MAXN=233;
const ll INF=1e18;
ll read(){
	ll x=0;bool f=1;char s=getchar();
	while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
	while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
	return f?x:-x;
}
int ptf[50],lpt;
void print(ll x,char c='\n'){
	if(x<0)putchar('-'),x=-x;
	ptf[lpt=1]=x%10;
	while(x>9)x/=10,ptf[++lpt]=x%10;
	while(lpt>0)putchar(ptf[lpt--]^48);
	if(c>0)putchar(c);
}
const ll M[]={0,0,1073741827,1073741827,1073741833,1073741831,1073741827,1073741831,1073741833,1073741833,1073741831,1073741857,1073741833,1073741839,1073741831,1073741971,1073741857,1073742169,1073741833,1073741833,1073742361,1073741971,1073741857,1073741891,1073741833,1073742851,1073741839,1073741833,1073742209,1073742053,1073741971,1073742289,1073741857,1073741857,1073742169,1073741831,1073741833,1073742073,1073741833,1073741839,1073742361,1073742113,1073741971,1073741993,1073741857,1073742391,1073741891,1073742073,1073741857,1073742391,1073742851,1073742169,1073741969,1073742053,1073741833,1073742671,1073742209,1073741833,1073742053,1073741827,1073742361,1073747621,1073742289,1073742391,1073741953,1073741891,1073741857,1073742403,1073742169,1073742259,1073741831,1073745781,1073741833,1073743861,1073742073,1073743051,1073741833,1073742209,1073741839,1073742721,1073742721,1073741833,1073742113,1073745769,1073742517,1073743291,1073741993,1073742169,1073741857,1073743883,1073742391,1073742671,1073742673,1073742289,1073742073,1073744911,1073741857,1073742277,1073742391,1073742517,1073743501};
const int G[]={0,0,2,2,5,13,2,13,5,5,13,5,5,3,13,2,5,7,5,5,7,2,5,6,5,2,3,5,3,2,2,37,5,5,7,13,5,5,5,3,7,5,2,3,5,6,6,5,5,6,2,7,3,2,5,7,3,5,2,2,7,2,37,6,10,6,5,2,7,2,13,2,5,6,5,2,5,3,3,11,11,5,5,7,6,2,3,7,5,2,6,7,5,37,5,6,5,5,6,6,2};
ll ksm(ll a,ll b,ll mo){
	ll res=1;
	for(;b;b>>=1,a=a*a%mo)if(b&1)res=res*a%mo;
	return res;
}
int n,k,a[MAXN][MAXN],cnt[1<<20];
ll lm[MAXN][MAXN],c[MAXN][MAXN],MOD,g,ans;
mt19937_64 Rand(*new(int));
ll Gauss(int n){
	ll res=1;
	for(int i=1;i<=n;i++){
		if(!c[i][i]){
			for(int j=i+1;j<=n;j++)if(c[j][i]){
				for(int k=i;k<=n;k++)swap(c[i][k],c[j][k]);
				res=MOD-res;break;
			}if(!c[i][i])return 0;
		}(res*=c[i][i])%=MOD;
		ll gc=MOD-ksm(c[i][i],MOD-2,MOD);
		for(int j=i+1;j<=n;j++){
			ll cg=c[j][i]*gc%MOD;
			for(int k=i;k<=n;k++)(c[j][k]+=c[i][k]*cg)%=MOD;
		}
	}return res;
}
int main()
{
	freopen("sort.in","r",stdin);
	freopen("sort.out","w",stdout);
	n=read(),k=read();
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)a[i][j]=read();
	MOD=M[k],g=ksm(G[k],(MOD-1)/k,MOD);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)lm[i][j]=Rand()%(MOD-5)+4;
	for(int e=0;e<k;e++){
		ll w=ksm(g,e,MOD);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++){
				if(a[i][j]>=0)c[i][j]=lm[i][j]*ksm(w,a[i][j],MOD)%MOD;
				else c[i][j]=0;
			}
		(ans+=Gauss(n))%=MOD;
	}printf(ans?"Yes\n":"No\n");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值