1.1 Description
送你一个n 个点m 条边的DAG 和参数k, 定义一条经过l 条边的路径的权值为l^k.
对于i=1…n, 求出所有1 到i 的路径的权值之和, 对998244353 取模.
1.2 Input Format
第一行三个整数n; m; k, 分别表示DAG 的点数, 边数和参数.
接下来m 行, 每行两个整数ui; vi, 表示一条从ui 到vi 的有向边.
1.3 Output Format
共输出n 行, 第i 行一个整数, 表示i 号点的答案.
1.4 Sample
1.4.1 Input
6 8 2
1 2
1 3
1 5
2 4
3 2
3 4
3 6
4 6
1.4.2 Output
0
5
1
17
1
38
1.5 Constraints
对于前20% 的数据, n 2000;m 5000;
对于另10% 的数据, k = 1;
对于另20% 的数据, k =30;
对于100% 的数据, 1 n 100000; 1 m 200000; 0 k 500, 保证从1 出发可以到达每
个点, 可能会有重边.
发现k的值比较小,那么不妨设f[i][x]表示到第i个点所有路径的x次方的和,使用二项式定理可以搞到nk2nk2
但是现在要搞到nk
f[i][x]=∑len(i)xf[i][x]=∑len(i)x
这里需要使用第二类斯特林树
第二类斯特林树表示的是把n个有特征的球放入m个没有特征的盒子的方案数(每一个盒子里面都至少有一个球),一般也可以用{nmmn}或s[n][m]来表示
考虑一下mnmn的数学意义,就是把n个本质不同的数放到m个不同的盒子里面,这就等于选出x(x=1..m)个盒子然后再放球的总方案数,即:mn=∑mi=1s[n][i]∗mi−mn=∑i=1ms[n][i]∗m−i,也就是先一个排列选出要的盒子,再一个第二类斯特林数
那么套进去这一题里面呢?
len(p)k=∑ki=1s[k][i]∗len(p)i−len(p)k=∑i=1ks[k][i]∗len(p)−i
最后一段是一个排列,我们把它除上一个j!让它变成一个组合数
就是
∑ki=1s[k][i]∗i!∗Cilen(p)∑i=1ks[k][i]∗i!∗Clen(p)i
其中len(p)表示一条长度为p的路径
那么我们可以设f[x][i]=∑Cilen(p)f[x][i]=∑Clen(p)i,这个可以有杨奎三角定义O(1)转移
然后剩下的问题就是求s[n][m]了
考虑使用递推,s[n][m]=s[n-1][m]*m+s[n-1][m-1]
第一段表示新加进来的一段加到一个原来就有的集合里面,后面的那一段表示我把新加入的数放到了一个新的集合里面
这样就完美解决本题了~
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define ll long long
using namespace std;
const int maxn=1e5+5,md=998244353;
ll f[maxn][505],g[505][505];
int fi[maxn],ne[maxn*2],dui[maxn*2],qc[maxn];
int ru[maxn],h[maxn];
int i,j,k,l,m,n,x,y,now,p,z;
ll ans,s;
void add(int x,int y){
if (fi[x]==0) fi[x]=++now; else ne[qc[x]]=++now;
dui[now]=y; qc[x]=now;
}
int main(){
freopen("t1.in","r",stdin);
freopen("t1.out","w",stdout);
scanf("%d%d%d",&n,&m,&p);
fo(i,1,m){
scanf("%d%d",&x,&y); add(x,y); ru[y]++;
}
h[1]=1; i=1; j=0;
f[1][0]=1;
while (i>j){
x=h[++j];
k=fi[x];
while (k){
f[dui[k]][0]=(f[dui[k]][0]+f[x][0])%md;
fo(z,1,p) f[dui[k]][z]=(f[dui[k]][z]+(f[x][z]+f[x][z-1])%md)%md;
ru[dui[k]]--;
if (!ru[dui[k]]) h[++i]=dui[k];
k=ne[k];
}
}
g[0][0]=1;
fo(i,1,p)
fo(j,0,p){
g[i][j]=(1ll*j*g[i-1][j])%md;
if (j) g[i][j]=(g[i][j]+g[i-1][j-1])%md;
}
fo(i,1,n){
s=1; ans=0;
fo(j,1,p){
if (j) s=(s*j)%md;
ans=(ans+((s*g[p][j])%md)*f[i][j])%md;
}
printf("%lld\n",ans);
}
return 0;
}