[luogu7736]路径交点

对于两条路径,注意到每一个交点都会改变两者的上下关系,因此两条路径交点的奇偶性,仅取决于两者的起点和终点是否改变了上下关系(改变即为奇数)

类似地,对于整个路径方案,令$p_{i}$为以第一层的$i$为起点的路径在第$K$层的终点,那么该方案的交点数的奇偶性,仅取决于$p_{i}$​逆序对数(与逆序对数的奇偶性相同)

但注意到方案还有一个限制:不允许经过重复的点

但事实上,当经过了重复的点,显然将之后的两部分交换,恰好会改变$p_{i}$​​逆序对数的奇偶性

更准确的来说,考虑起点编号最小的两条有公共点的路径,将两者第一个公共点以后的部分交换,显然反过来另一条路径对应的也是原路径,即可以抵消

由此,令$A_{i,j}$​表示起点为第一层的$i$​且终点为第$K$​层的$j$​,显然答案即为$A$​的行列式,可以$o(n^{3})$求出

关于如何求$A$​,令$G_{i}$​为第$i$​层和第$i+1$​层之间的邻接矩阵(大小为$n_{i}\times n_{i+1}$​​)​​,显然$A=\prod_{i=1}^{k-1}G_{i}$(其中乘法为矩阵乘法),可以$o(kn^{3})$求出​

(单组数据)总复杂度为$o(kn^{3})$​​​,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 205
 4 #define mod 998244353
 5 #define ll long long
 6 int t,K,x,y,ans,n[N],m[N],a[N][N][N],b[N][N],c[N][N];
 7 int read(){
 8     int x=0;
 9     char c=getchar();
10     while ((c<'0')||(c>'9'))c=getchar();
11     while ((c>='0')&&(c<='9')){
12         x=x*10+c-'0';
13         c=getchar();
14     }
15     return x;
16 }
17 int qpow(int n,int m){
18     int s=n,ans=1;
19     while (m){
20         if (m&1)ans=(ll)ans*s%mod;
21         s=(ll)s*s%mod;
22         m>>=1;
23     }
24     return ans;
25 }
26 int guess(int n){
27     int ans=1;
28     for(int i=1;i<=n;i++){
29         int k=-1;
30         for(int j=i;j<=n;j++)
31             if (b[j][i]){
32                 k=j;
33                 break;
34             }
35         if (k<0)return 0;
36         if (k!=i){
37             ans=mod-ans;
38             for(int j=i;j<=n;j++)swap(b[i][j],b[k][j]);
39         }
40         ans=(ll)ans*b[i][i]%mod;
41         int s=qpow(b[i][i],mod-2);
42         for(int j=i;j<=n;j++)b[i][j]=(ll)b[i][j]*s%mod;
43         for(int j=i+1;j<=n;j++){
44             int s=b[j][i];
45             for(int k=i;k<=n;k++)b[j][k]=(b[j][k]-(ll)s*b[i][k]%mod+mod)%mod;
46         }
47     }
48     return ans;
49 }
50 int main(){
51     t=read();
52     while (t--){
53         K=read();
54         for(int i=1;i<=K;i++)n[i]=read();
55         for(int i=1;i<K;i++)m[i]=read();
56         memset(a,0,sizeof(a));
57         for(int i=1;i<K;i++)
58             for(int j=1;j<=m[i];j++){
59                 x=read(),y=read();
60                 a[i][x][y]=1;
61             }
62         memset(b,0,sizeof(b));
63         for(int i=1;i<=n[1];i++)b[i][i]=1;
64         for(int t=1;t<K;t++){
65             memset(c,0,sizeof(c));
66             for(int i=1;i<=n[1];i++)
67                 for(int j=1;j<=n[t];j++)
68                     for(int k=1;k<=n[t+1];k++)c[i][k]=(c[i][k]+(ll)b[i][j]*a[t][j][k])%mod;
69             memcpy(b,c,sizeof(b));
70         }
71         printf("%d\n",guess(n[1]));
72     }
73     return 0;
74 }
View Code

 

posted @ 2021-07-27 20:09  PYWBKTDA  阅读(69)  评论(0编辑  收藏  举报