【行列式】交易(省选模拟Day3)(2022.9.23)

交易 Orzcyr

【问题描述】

给定 n 点 m 边有向无环图,其中没有入度的点被视为源点,没有出度的点被视为
汇点。保证源点和汇点数目相同。
考虑所有把源汇点两两配对,用两两点不相交的路径把它们两两连接的所有方案
如果这个方案中,把源点按标号排序后,得到的对应汇点序列的逆序数对的个数
是奇数,那么 A 给 B 一块钱,否则 B 给 A 一块钱。
问最后 A 的收益,对一个 p 取模。n,m,p 均为整数,p 为质数。

【输入格式】

第一行读入三个数,n,m,p,接下来 m 行,读入有向边。

【输出格式】

一行,输出答案。

【样例输入】

4 4 1000003
2 1
2 4
3 1
3 4

【样例输出】

0
【数据规模与约定】
对于 30%的数据,n<=100
对于 100%的数据,1<=n<=600,1<=m<=50000

一看答案逆序对形式即行列式(关于行列式是什么以及行列式的基本变换请自行百度)
把图跑一边求出行列式,类似高消求出行列式的值即答案。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(w>'9'||w<'0'){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(w>='0'&&w<='9'){
		j=(j<<3)+(j<<1)+w-'0';
		w=getchar();
	}
	return f*j;
}
#define int long long
const int N=601,M=100001;
int n,m,mod,s[N],t[N],f[N][N],sum[N][N],ru[N],chu[N],s_len,t_len;
int head[N],to[M],fro[M],tail;
inline void addline(int x,int y){
	to[++tail]=y;
	fro[tail]=head[x];
	head[x]=tail;
	ru[y]++,chu[x]++;
	return ;
}
void bfs(){
	deque<int>p;
	for(int i=1;i<=s_len;i++)p.push_back(s[i]),sum[s[i]][s[i]]=1;
	while(!p.empty()){
		int u=p.front();p.pop_front();
		for(int k=head[u];k;k=fro[k]){
			int x=to[k];
			ru[x]--;
			if(!ru[x])p.push_back(x);
			for(int i=1;i<=s_len;i++)sum[s[i]][x]+=sum[s[i]][u],sum[s[i]][x]%=mod;
		}
	}
	return ;
}
inline int fastpow(int x,int y){
	int ansn=1;
	while(y){
		if(y&1)ansn=1ll*ansn*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return ansn;
}
int gaos(){
	int len=s_len,num=1,ans=1;
	for(int i=1;i<=len;i++){
		if(!f[i][i]){
			int cnt=0;
			for(int j=i+1;j<=n;j++){
				if(f[j][i]){
					swap(f[i],f[j]),num*=-1,cnt++;
					break;
				}
			}
			if(!cnt)return 0;
		}
		for(int j=i+1;j<=len;j++){
			if(!f[j][i])continue;
			long long k=mod-1ll*fastpow(f[i][i],mod-2)*f[j][i]%mod;
			for(int l=i;l<=len;l++)f[j][l]=(f[j][l]+1ll*f[i][l]*k%mod)%mod;
		}
	}
	for(int i=1;i<=len;i++)ans=1ll*ans*f[i][i]%mod;
	ans=(ans*num+mod)%mod;
	return ans;
} 
signed main(){
	n=rd(),m=rd(),mod=rd();
	for(int i=1;i<=m;i++){
		int x=rd(),y=rd();
		addline(x,y);
	}
	for(int i=1;i<=n;i++){
		if(!chu[i])t[++t_len]=i;
		if(!ru[i])s[++s_len]=i;
	}
	bfs();
	for(int x=1;x<=s_len;x++){
		for(int y=1;y<=t_len;y++){
			f[x][y]=sum[s[x]][t[y]]%mod;
		}
	}
	printf("%d",gaos());
	return 0;
}
posted @   flywatre  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示