P7736 [NOI2021] 路径交点
P7736 [NOI2021] 路径交点
题意
给一个分层 DAG,起点和终点(第一层和最后一层)数量相同,要求路径没有公共点。问所有路径方案中,\(偶数交点方案数-奇数交点方案数\) 是多少。
思路
对于相邻两层,我们每层各选择 \(n\) 个点。题目说的“交点数”其实就是排列的逆序对数。建邻接矩阵,边权为 \(1\)。对邻接矩阵生成的所有 \(n\times n\) 的子方阵,套 LGV 引理,求行列式。然后相加。
然后你发现你不能枚举选择哪 \(n\) 个点啊,因此这里我们规定相邻两层的节点数都恰好是 \(n\)。
对于多层的,使用比内柯西公式解决,题目保证第一层和最后一层都是 \(n\) 个点,使得题目可做。
在第一层和最后一层之间加一层,分别构造两个邻接矩阵 \(A,B\),表示第一层和中间层,最后一层和中间层的连边关系。
思考 \(|AB|\) 的含义。等于所有在 \(A\) 中选择 \(n\) 列(中间层选择 \(n\) 个点),在 \(B\) 中选择对应的 \(n\) 行(中间层选择对应的 \(n\) 个点)。两个方阵的行列式相乘,就是一个卷积形式,就是每种方案的贡献相乘,发现是对的。(过几天我将会看不懂我在说什么)
然后由于矩阵乘法满足结合律,因此所有邻接矩阵连乘,的行列式,就是答案!
时间复杂度 \(O(n^4)\)。常数小吧。
code
#include<bits/stdc++.h>
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
namespace pragmatic {
constexpr int N=205,mod=998244353;
int add(int a,int b) { return a+b>=mod ? a+b-mod : a+b; }
void _add(int &a,int b) { a=add(a,b); }
int mul(int a,int b) { return 1ll*a*b%mod; }
void _mul(int &a,int b) { a=mul(a,b); }
int t,k;
int n,m[N];
int u,v;
struct juzhen {
int n,m;
int x[N][N];
void clear() { memset(x,0,sizeof(x)); }
juzhen operator * (const juzhen b) const {
juzhen c={n,b.m};
c.clear();
rep(i,1,c.n) rep(j,1,c.m) {
rep(k,1,m) _add(c.x[i][j],mul(x[i][k],b.x[k][j]));
}
return c;
}
}a[N];
int f;
int ksm(int a,int b=mod-2) {
int s=1;
while(b) {
if(b&1) _mul(s,a);
_mul(a,a);
b>>=1;
}
return s;
}
void _swap(juzhen &a,int x,int y) {
f^=1;
rep(i,1,a.n) swap(a.x[x][i],a.x[y][i]);
}
void gauss(juzhen &a) {
rep(i,1,a.n) {
if(!a.x[i][i])
rep(j,i+1,a.n) {
if(a.x[j][i]) {
_swap(a,i,j);
break;
}
}
int inv=ksm(a.x[i][i]);
rep(j,i+1,a.n) {
if(!a.x[j][i]) continue;
int t=mul(inv,a.x[j][i]);
rep(k,i,a.n) _add(a.x[j][k],mod-mul(t,a.x[i][k]));
}
}
}
int det(juzhen &a) {
f=0;
gauss(a);
int ans=1;
rep(i,1,a.n) {
_mul(ans,a.x[i][i]);
}
if(f) return add(mod,-ans);
return ans;
}
void main() {
sf("%d",&t);
while(t--) {
sf("%d",&k);
rep(i,1,k) sf("%d",&n), a[i].n=n;
rep(i,1,k-1) a[i].m=a[i+1].n;
rep(i,1,k-1) sf("%d",&m[i]);
rep(i,1,k-1) a[i].clear();
rep(i,1,k-1) {
rep(j,1,m[i]) {
sf("%d%d",&u,&v);
a[i].x[u][v]=1;
}
}
rep(i,2,k-1) a[1]=a[1]*a[i];
pf("%d\n",det(a[1]));
}
}
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("my.out","w",stdout);
#endif
pragmatic :: main();
}
本文来自博客园,作者:wing_heart,转载请注明原文链接:https://www.cnblogs.com/wingheart/p/18648852

浙公网安备 33010602011771号