1 条题解

  • 0
    @ 2026-9-24 10:25:48

    宝宝容斥。

    记 Anss,t,k\text{Ans}_{s,t,k} 表示从 ss 走到 tt 中途不经过 s,ts,t 且恰好走 kk 步的答案。发现直接处理只能限定 s,ts,t 中一端不经过,故我们需要容斥。我们钦定路径 ss 一端始终没有重复经过,容斥去 tt 的重复经过。此时总方案数为从 ss 走 kk 步到 tt 但中途不重复经过 ss 的方案数,记之为 fs,t,kf_{s,t,k}。对于重复经过 tt 但不重复经过 ss 的非法路径,划分其为两阶段,枚举第一次经过 tt 走了 dd 步,首先从 ss 走 dd 步到 tt 且都不经过 s,ts,t,再从 tt 走 k−dk-d 步回到 tt,但是不经过 ss,其中 1≤d<k1\le d<k。发现一阶段的方案数就是 Anss,t,d\text{Ans}_{s,t,d},记 gs,t,kg_{s,t,k} 表示从 ss 走 kk 步回到 ss 但不经过 tt 的方案数,那么二阶段方案数为 gt,s,k−dg_{t,s,k-d}。于是我们有:

    $$\text{Ans}_{s,t,k}=f_{s,t,k}-\sum_{d=1}^{k-1}\text{Ans}_{s,t,d}\times g_{t,s,k-d}.$$

    ff 是好处理的,枚举起点 ss,初始 fs,s,0=1f_{s,s,0}=1,枚举步数 dd,转移 trivial:fs,u,d→fs,v,d+1f_{s,u,d} \to f_{s,v,d+1},要求存在边 (u,v)(u,v) 且 v≠sv \ne s。

    考虑如何处理 gg。再次容斥。用 tt 走 kk 步回到 tt 的总方案数减去其中经过了 ss 的非法方案数。记 hs,t,kh_{s,t,k} 表示 ss 走 kk 步到 tt 无任何限制的方案数,总方案数即 hs,s,kh_{s,s,k}。对于非法路径,我们类似地划分其为两阶段,枚举最后一次经过 tt 走了 dd 步,首先从 ss 走 dd 步到 tt 无其他限制,再从 tt 走 k−dk-d 步回到 ss 但中途不重复回到 tt。前者即 hs,t,dh_{s,t,d},后者即 ft,s,k−df_{t,s,k-d}。于是我们有:

    $$g_{s,t,k}=h_{s,s,k}-\sum_{d=1}^{k-1} h_{s,t,d}\times f_{t,s,k-d}.$$

    hh 类似 ff,处理 naive。初始 hs,s,0=1h_{s,s,0}=1,枚举步数 dd,转移 hs,u,d→hs,v,dh_{s,u,d}\to h_{s,v,d},只要求 (u,v)(u,v) 有边。

    得到 gg 后处理 Ans\text{Ans}。最后 O(1)O(1) 输出答案。处理 f,hf,h 复杂度 O(n3d)O(n^3d),处理 g,Ansg,\text{Ans} 复杂度 O(n2d2)O(n^2d^2)。

    #include <bits/stdc++.h>
    #define LL long long
    #define ull unsigned long long
    #define uint unsigned int
    using namespace std;
    const int N = 110;
    const int M = 55;
    int n, Q, m; ull P; bool e[N][N];
    ull F[M][N][N], H[M][N][N], Ans[M][N][N], G[M][N][N];
    int main() {
    	freopen(".in", "r", stdin); freopen(".out", "w", stdout);
    	ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
    	cin >> n >> m >> P;
    	for (int i = 1, u, v; i <= m; i ++)
    		cin >> u >> v, e[u][v] = 1;
    	for (int s = 1; s <= n; s ++) {
    		F[0][s][s] = H[0][s][s] = 1;
    		for (int k = 1; k <= 50; k ++) for (int t = 1; t <= n; t ++) for (int v = 1; v <= n; v ++)
    			if (e[t][v]) (H[k][s][v] += H[k - 1][s][t]) %= P;
    		for (int k = 1; k <= 50; k ++) for (int t = 1; t <= n; t ++) for (int v = 1; v <= n; v ++)
    			if (e[t][v] && v != s) (F[k][s][v] += F[k - 1][s][t]) %= P;
    	}
    	for (int s = 1; s <= n; s ++) for (int t = 1; t <= n; t ++) if (s != t) {
    		for (int k = 1; k <= 50; k ++) {
    			for (int d = 1; d < k; d ++) 
    				G[k][s][t] = (G[k][s][t] + H[d][s][t] * F[k - d][t][s] % P) % P;
    			G[k][s][t] = (H[k][s][s] + P - G[k][s][t]) % P;
    		}
    	}
    	for (int s = 1; s <= n; s ++) for (int t = 1; t <= n; t ++) if (s != t) {
    		for (int k = 1; k <= 50; k ++) {
    			for (int d = 1; d < k; d ++)
    				Ans[k][s][t] = (Ans[k][s][t] + Ans[d][s][t] * G[k - d][t][s] % P) % P;
    			Ans[k][s][t] = (F[k][s][t] + P - Ans[k][s][t]) % P;
    		}
    	}
    	cin >> Q; int x, y, k;
    	while (Q --) {
    		cin >> x >> y >> k; cout << Ans[k][x][y] << "\n";
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    5765
    时间
    10000ms
    内存
    356MiB
    难度
    10
    标签
    递交数
    3
    已通过
    1
    上传者