F - Teleporting Takahashi 2
Time Limit: 3 sec / Memory Limit: 1024 MB
Score : 525 points
Problem Statement
There is a simple directed graph G with N vertices and N+M edges. The vertices are numbered 1 to N, and the edges are numbered 1 to N+M.
Edge i (1≤i≤N) goes from vertex i to vertex i+1. (Here, vertex N+1 is considered as vertex 1.)
Edge N+i (1≤i≤M) goes from vertex Xi to vertex Yi.
Takahashi is at vertex 1. At each vertex, he can move to any vertex to which there is an outgoing edge from the current vertex.
Compute the number of ways he can move exactly K times.
That is, find the number of integer sequences (v0,v1,…,vK) of length K+1 satisfying all of the following three conditions:
- 1≤vi≤N for i=0,1,…,K.
- v0=1.
- There is a directed edge from vertex vi−1 to vertex vi for i=1,2,…,K.
Since this number can be very large, print it modulo 998244353.
Constraints
- 2≤N≤2×10^5
- 0≤M≤50
- 1≤K≤2×10^5
- 1≤Xi,Yi≤N, Xi≠Yi
- All of the N+M directed edges are distinct.
- All input values are integers.
Input
The input is given from Standard Input in the following format:
N M K X1 Y1 X2 Y2 ⋮ XM YM
Output
Print the count modulo 998244353.
Sample Input 1
6 2 5 1 4 2 5
Sample Output 1
5
The above figure represents the graph G. There are five ways for Takahashi to move:
- Vertex 1→ Vertex 2→ Vertex 3→ Vertex 4→ Vertex 5→ Vertex 6
- Vertex 1→ Vertex 2→ Vertex 5→ Vertex 6→ Vertex 1→ Vertex 2
- Vertex 1→ Vertex 2→ Vertex 5→ Vertex 6→ Vertex 1→ Vertex 4
- Vertex 1→ Vertex 4→ Vertex 5→ Vertex 6→ Vertex 1→ Vertex 2
- Vertex 1→ Vertex 4→ Vertex 5→ Vertex 6→ Vertex 1→ Vertex 4
Sample Input 2
10 0 200000
Sample Output 2
1
Sample Input 3
199 10 1326 122 39 142 49 164 119 197 127 188 145 69 80 6 120 24 160 18 154 185 27
Sample Output 3
451022766
【思路分析】
二维dp+二分+缩点。由于要求方案数,且一定存在一条最大环,可以在这条环上做dp。其中dp[i][j]表示路线以编号i结尾,走过j步的方案数。度为2的节点显然有dp[i+1][j] = dp[i][j-1],其它点模拟即可。
由于n和k较大,即使dp降维也会tle。考虑缩点,将多个度为2的连续点缩点。重新建图,原m条分支需要重新指向新下标,采用前缀+二分寻找新下标。
依次迭代dp,在最后对答案累加时,由于缩点,每个点记录的是该点集的最小编号,显然只累加dp[i][k]是只考虑了一个点。设sz为点集中点总数,则该缩点对答案的贡献为dp[i][k-sz+1]+...+dp[i][k]。
该方法的时间复杂度为,空间复杂度为,符合题意。
#include<bits/stdc++.h>
#define i64 long long
#define ll long long
using namespace std;
const i64 MOD = 998244353;
const i64 N = 2e5 + 5;
vector<int> G[N], refl[205];
i64 dp[205][N], E[205], pre[205];
bool ind[N];
void solve() {
i64 n, m, k;
cin >> n >> m >> k;
if (m == 0) {
cout << 1;
return;
}
//存点
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
G[u].emplace_back(v);
ind[v] = true;
}
//缩点建新图
i64 idx = 1;
for (int i = 1; i <= n; ++i, ++idx) {
if (G[i].empty()&&!ind[i]) {
while (i <= n && G[i].empty() && !ind[i]) {
E[idx]++;
++i;
}
--i;
} else if (G[i].empty()) {
E[idx] = 1;
} else {
refl[idx].resize(G[i].size());
copy(G[i].begin(), G[i].end(), refl[idx].begin());
}
if (i > n) break;
pre[idx] = pre[idx - 1] + (E[idx] == 0 ? 1 : E[idx]);
}
//重连边
--idx;
for (int i = 1; i <= idx; ++i) {
if (E[i] == 0) {
for (int &item: refl[i]) {
item = lower_bound(pre + 1, pre + idx, item) - pre;
}
}
}
//dp过程
dp[1][0] = 1;
for (int i = 1; i <= k; ++i) {
for (int j = 1; j < idx; ++j) {
if (E[j] == 0) {
for (const auto &item: refl[j]) {
dp[item][i] += dp[j][i - 1];
dp[item][i] %= MOD;
}
dp[j + 1][i] += dp[j][i - 1];
dp[j+1][i] %= MOD;
} else if (i >= E[j]) {
dp[j + 1][i] += dp[j][i - E[j]];
dp[j + 1][i] %= MOD;
}
}
if (E[idx] == 0) {
for (const auto &item: refl[idx]) {
dp[item][i] += dp[idx][i - 1];
dp[item][i] %= MOD;
}
dp[1][i] += dp[idx][i - 1];
dp[1][i] %= MOD;
} else if (i >= E[idx]) {
dp[1][i] += dp[idx][i - E[idx]];
dp[1][i] %= MOD;
}
}
//答案累加
i64 res = 0;
for (int i = 1; i <= idx; ++i) {
if (E[i] == 1 || E[i] == 0) {
res += dp[i][k];
res%=MOD;
}
else {
for (int j = max(k - E[i] + 1, 1ll); j <= k; ++j) {
res += dp[i][j];
res%=MOD;
}
}
res %= MOD;
}
cout << res % MOD;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t = 1;
// cin >> t;
while (t--) {
solve();
}
return 0;
}