保卫王国

题目大意:小 Y 正在 A 国游玩。该国共有 𝑛 个城市,地图可以抽象为一张有向无环图。小 Y 的旅行共有 𝑞 天,每天他都会选取一个新的起点和终点,同时每天都会有一些城市无法通行。现在小 Y 想要知道每一天他可能的旅行路线数量。

时隔很久,这个坑终于tmd补上了

和上学路线那个题目很相似,s到达t的方案数就等于从s到达t不算坏点的方案数,减去路径中经过换点的数目的dp值乘以这个坏点到达t的方案数

注意要提前预处理

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 66, mod = 1e9 + 7;

inline int read()
{
int s(0), w(1);
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') w = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}

inline void put(int x)
{
if (! x) putchar('0');
if (x < 0) putchar('-'), x = -x;
int num(0); char c[66];
while (x) c[++ num] = x % 10 + 48, x /= 10;
while (num) putchar(c[num --]);
return (void)(putchar('\n'));
}

int ver[N], nex[N], head[N], cnt;

inline void add_edge(int x, int y)
{
ver[++ cnt] = y;
nex[cnt] = head[x];
return (void)(head[x] = cnt);
}

int n, m, T;
int g[N], c[N], deg[N], vis[N];
int f[1010][1010];

inline void dfs(int x)
{
int i, j, y;
vis[x] = 1, f[x][x] = 1;
for (i = head[x]; i; i = nex[i])
{
y = ver[i];
if (! vis[y]) dfs(y);
for (j = 1; j <= n; ++ j)
(f[x][j] += f[y][j]) %= mod;
}
}

queue<int>q;

signed main()
{

int i, x, y;
n = read(), m = read(), T = read();
for (i = 1; i <= m; ++ i)
{
x = read(), y = read();
add_edge(x, y);
}

for (i = 1; i <= n; ++ i) if (! vis[i]) dfs(i);

while (T --)
{
int s = read(), t = read(), k = read();
memset(deg, 0, sizeof deg);
for (i = 1; i <= k; ++ i) c[i] = read();

int l, r;
for (l = 1; l <= k; ++ l)
{
for (r = 1; r <= k; ++ r)
{
if (l == r || ! f[c[l]][c[r]]) continue;
else ++ deg[r];
}
}
for (i = 1; i <= k; ++ i) if (! deg[i]) q.push(i);
for (i = 1; i <= k; ++ i) g[i] = f[s][c[i]];
while (! q.empty())
{
x = q.front(); q.pop();
for (i = 1; i <= k; ++ i)
{
if (i != x && f[c[x]][c[i]])
{
g[i] = (g[i] - 1ll * g[x] * f[c[x]][c[i]] % mod) % mod;
if (! -- deg[i]) q.push(i);
}
}
}
int res = f[s][t];
for (i = 1; i <= k; ++ i)
{
res = (res - 1ll * g[i] * f[c[i]][t] % mod) % mod;
}
res = (res % mod + mod) % mod;
put(res);
}

return 0;
}

总结:其实很多时候,只是自己骗自己:这题很难,细细拨开来看,一点都不难