[NOI2021] 路径交点

\(\text{Problem}:\)[NOI2021] 路径交点

\(\text{Solution}:\)

不难发现,每层路径的交点个数就是其对应排列的逆序对个数。答案又是求偶数减去奇数,容易联想到直接用行列式求解。现在只需求出 \(f_{1,x}\rightarrow f_{k,y}\) 的路径方案数,对这个矩阵用高斯消元求行列式即可。

注意到以上的做法并没有保证图中的每个顶点至多出现在一条路径中的条件,但是却是对的。设存在两条路径交于点 \(p\)。交换从 \(p\) 出发的两条边,可以让逆序对的奇偶性改变,故不影响答案。

\(f_{1,x}\rightarrow f_{k,y}\) 的路径方案数利用矩阵乘法计算即可。总时间复杂度 \(O(Tn^3k)\)

\(\text{Code}:\)

#include <bits/stdc++.h>
//#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=210, Mod=998244353;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int K,n[N],m[N],a[N][N];
inline int Det(int n)
{
	int res=1;
	for(ri int i=1;i<=n;i++)
	{
		for(ri int j=i+1;j<=n;j++)
		{
			while(a[i][i])
			{
				int w=a[j][i]/a[i][i];
				for(ri int k=i;k<=n;k++)
				{
					a[j][k]=(a[j][k]-1ll*a[i][k]*w%Mod+Mod)%Mod;
				}
				for(ri int k=1;k<=n;k++) swap(a[i][k],a[j][k]);
				res=-res;
			}
			for(ri int k=1;k<=n;k++) swap(a[i][k],a[j][k]);
			res=-res;
		}
	}
	for(ri int i=1;i<=n;i++) res=1ll*res*a[i][i]%Mod;
	return (res+Mod)%Mod;
}
struct Mat
{
	int a[N][N],n,m;
	inline Mat () { memset(a,0,sizeof(a)); }
};
inline Mat operator * (Mat x,Mat y)
{
	Mat res;
	for(ri int i=1;i<=x.n;i++)
	for(ri int k=1;k<=x.m;k++)
	for(ri int j=1;j<=y.m;j++)
	res.a[i][j]=(res.a[i][j]+1ll*x.a[i][k]*y.a[k][j]%Mod)%Mod;
	res.n=x.n, res.m=y.m;
	return res;
}
signed main()
{
	for(ri int T=read();T;T--)
	{
		K=read();
		for(ri int i=1;i<=K;i++) n[i]=read();
		for(ri int i=1;i<K;i++) m[i]=read();
		Mat f;
		f.n=f.m=n[1];
		for(ri int i=1;i<=f.n;i++) f.a[i][i]=1;
		for(ri int i=1;i<K;i++)
		{
			Mat g;
			g.n=n[i], g.m=n[i+1];
			for(ri int j=1;j<=m[i];j++)
			{
				int u,v;
				u=read(), v=read();
				g.a[u][v]=1;
			}
			f=f*g;
		}
		for(ri int i=1;i<=f.n;i++)
		for(ri int j=1;j<=f.m;j++) a[i][j]=f.a[i][j];
		printf("%d\n",Det(f.n));
	}
	return 0;
}
posted @ 2021-07-29 08:50  zkdxl  阅读(78)  评论(0编辑  收藏  举报