【问题描述】
给定⼀张 n 个点,m 条边的有向图,保证⽆重边,⽆⾃环,点的标号
是 1…n。
现在有 Q 次询问,每次给出 S,T,D,求有多少起点为 S,终点为 T,
经过边数为 D 的路径,满⾜只在起点或终点处经过 S 和 T(即中途不能经
过 S 和 T)。
注意路径不要求是简单路径,也就是说可以多次经过同⼀个点、同⼀
条边。
你只需要输出答案对某个给定的常数 P 取模后的值即可
1 ≤ n ≤ 100 , 0 ≤ m ≤ n ∗ ( n − 1 ) , 1 ≤ D ≤ 50 , 2 ≤ P ≤ 1 0 9 , 1 ≤ Q ≤ 5 ∗ 1 0 5 。 1 ≤ n ≤ 100,0 ≤ m ≤ n ∗ (n−1),1 ≤ D ≤ 50, 2 ≤ P ≤ 10^9,1 ≤ Q ≤ 5 ∗ 10^5。 1≤n≤100,0≤m≤n∗(n−1),1≤D≤50,2≤P≤109,1≤Q≤5∗105。
s
o
l
u
t
i
o
n
solution
solution:
比较标准的容斥。
令
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]表示
i
i
i走
k
k
k步到
j
j
j且中途不经过
i
i
i的方案数
s
[
i
]
[
j
]
[
k
]
s[i][j][k]
s[i][j][k]表示
i
i
i走
k
k
k步到
j
j
j的方案数
t
[
i
]
[
j
]
[
k
]
t[i][j][k]
t[i][j][k]表示
i
i
i走
k
k
k步到
j
j
j,且中途不经过
j
j
j的方案数
g
[
i
]
[
j
]
g[i][j]
g[i][j]表示
i
i
i走
j
j
j步到
i
i
i且中途不经过
i
i
i的方案数
a
n
s
[
i
]
[
j
]
[
k
]
ans[i][j][k]
ans[i][j][k]表示
i
i
i走
k
k
k步到
j
j
j的答案
s
s
s和
f
f
f可以直接求
g
g
g可以直接由
f
f
f得到
t
t
t可以由
f
f
f和
g
g
g容斥到
a
n
s
ans
ans可以由
a
n
s
,
s
,
g
ans,s,g
ans,s,g容斥到
代码写得比较沙雕,其实可以放在一起处理
#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x],y = e[i].y;i;i = e[i].n,y = e[i].y)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
namespace fastIO{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
bool IOerror = 0;
inline char nc(){
static char buf[BUF_SIZE],*p1 = buf+BUF_SIZE, *pend = buf+BUF_SIZE;
if(p1 == pend){
p1 = buf; pend = buf+fread(buf, 1, BUF_SIZE, stdin);
if(pend == p1){ IOerror = 1; return -1;}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
inline int rd(){
bool sign = 0; char ch = nc();int x = 0;
for(; blank(ch); ch = nc());
if(IOerror)return 0;
if(ch == '-') sign = 1, ch = nc();
for(; ch >= '0' && ch <= '9'; ch = nc()) x = x*10+ch-'0';
if(sign) x = -x;
return x;
}
#undef OUT_SIZE
#undef BUF_SIZE
};
using namespace fastIO;
int n,m,p,Q;
int linkk[110],t;
struct node{int n,y;}e[10100];
int f[110][110][60],g[110][60],s[110][110][60];
int ans[110][110][60];
inline int mul(int a,int b){return 1ll*a*b%p;}
inline int del(int a,int b){return (a-=b)<0?a+=p:a;}
inline void add(int &a,int b){a += b;if(a >= p) a -= p;}
void insert(int x,int y){e[++t].y = y;e[t].n = linkk[x];linkk[x] = t;}
void solve(int v)
{
f[v][v][0] = 1;
rep(i,1,50) rep(x,1,n) rept(j,x) if((i==1)^(x!=v)) add(f[v][y][i],f[v][x][i-1]);
rep(i,1,50) g[v][i] = f[v][v][i];
s[v][v][0] = 1;
rep(i,1,50) rep(x,1,n) rept(j,x) add(s[v][y][i],s[v][x][i-1]);
}
int cnt;
int tmp[60];
int get(int i,int j,int t)
{
int now = g[i][t];
rep(k,1,t-1)
now = del(now,mul(ans[i][j][k],s[j][i][t-k]));
return now;
}
void init()
{
int x,y;n = rd();m = rd();p = rd();
rep(i,1,m)
{
x = rd();y = rd();
insert(x,y);
}
rep(i,1,n) solve(i);
//f[i][j][k]:i走k步到j,不经过i
//g[i][j],i走j步到i,不过i
//s[i][j][k]:i走k步到j,无限制
rep(i,1,n) rep(j,1,n) if(i!=j)
repp(k,50,2) rep(t,1,k-1)
s[i][j][k] = del(s[i][j][k],mul(s[i][j][t],g[j][k-t]));
//s[i][j][k]:i走k步到j,不经过j
rep(i,1,n) rep(j,1,n) if(i!=j)
rep(k,1,50)//i走k步到j,双限制
{
ans[i][j][k] = s[i][j][k];
rep(t,1,k-1)
ans[i][j][k] = del(ans[i][j][k],mul(get(i,j,t),s[i][j][k-t]));
}
Q = rd();
rep(i,1,Q)
{
int x = rd(),y = rd(),D = rd();
if(x == y) printf("%d\n",g[x][D]);
else printf("%d\n",ans[x][y][D]);
}
}
int main()
{
init();
return 0;
}