Description
給出一個 n 個點 m 條邊的 DAG 和參數 k。
定義一條經過 l 條邊的路徑的權值為 lk. 對于 i = 1…n, 求出所有 1 到 i 的路徑的權值之和, 對 998244353 取模.
對于前 20% 的資料, n ≤ 2000,m ≤ 5000;
對于另 10% 的資料, k = 1;
對于另 20% 的資料, k ≤ 30;
對于 100% 的資料, 1 ≤ n ≤ 100000,1 ≤ m ≤ 200000,0 ≤ k ≤ 500, 保證從 1 出發可以到達每 個點, 可能會有重邊.
Solution
設 Fi,j 表示到第i個點長度為j的路徑有多少條
直接轉移,最後算答案。
複雜度N^2
考慮優化
假設到u這個點有長度為a,b,c的三條路徑
要從 ak+bk+ck 轉移到 (a+1)k+(b+1)k+(c+1)k
二項式展開,組合數提出來
變成 ∑i=0kCik(ai+bi+ci)
與a,b,c具體無關,隻和a,b,c的i次方和有關,即當k=i時u這個點的答案
那麼狀态可以改成 Fi,j 表示i這個點當k=j時的答案
轉移是O(NK^2)的,即使用NTT優化也過不去
回到最原本的式子
Ansi=∑len(i)k
此處有關于第二類斯特林數的公式
nm=∑i=0nS(m,i)Pin
考慮其組合意義,S(m,i)表示m個有差别的球放入i個無差别的盒子中,要求盒子非空的方案數, nm 是m個有差别的球,n個有差别的盒子随便亂放,式子就是枚舉多少個盒子非空然後放球
那麼
Ansi=∑∑j=0len(i)S(k,j)Pjlen(i)
根據斯特林數的意義,j>k時顯然S為0,再把P拆成C*階乘,交換主體
=∑j=0len(i)j!S(k,j)∑Cjlen(i)
那麼現在改變狀态,設 Fi,j 表示第i個點的 ∑Cjlen(i)
根據楊輝三角,可以看出 Fi′,j=Fi,j+Fi,j−1
于是可以O(1)轉移,最後再統計答案
複雜度O(MK)
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#define N 100005
#define M 505
#define mo 998244353
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
LL f[][],s1[N],h[N];
int n,m,lim,nt[*N],fs[N],dt[*N],d[N],rd[N],mx[N],m1;
LL cf[];
void make()
{
int l=,r=;
fo(i,,n) if(rd[i]==) d[++r]=i;
f[][]=;
while(l<r)
{
int k=d[++l];
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
rd[p]--;
if(rd[p]==) d[++r]=dt[i];
mx[p]=max(mx[p],mx[k]+);
fo(j,,mx[k])
{
(f[p][j+]+=f[k][j])%=mo;
}
}
}
fo(i,,n)
{
LL s=;
fo(j,,mx[i])
{
s=(s+f[i][j]*cf[j]%mo)%mo;
}
printf("%lld\n",s);
}
}
LL ksm(LL k,LL n)
{
LL s=;
for(;n;k=k*k%mo,n>>=) if(n&) s=s*k%mo;
return s;
}
void link(int x,int y)
{
nt[++m1]=fs[x];
dt[fs[x]=m1]=y;
}
int main()
{
cin>>n>>m>>lim;
fo(i,,m)
{
int x,y;
scanf("%d%d",&x,&y);
link(x,y);
rd[y]++;
}
if(lim==)
{
int l=,r=;
fo(i,,n) if(rd[i]==) d[++r]=i;
h[]=,s1[]=;
while(l<r)
{
int k=d[++l];
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
rd[p]--;
if(rd[p]==) d[++r]=dt[i];
s1[p]=(s1[p]+s1[k]+h[k])%mo;
h[p]=(h[p]+h[k])%mo;
}
}
fo(i,,n) printf("%lld\n",s1[i]);
}
else
{
fo(i,,n) cf[i]=ksm(i,lim);
make();
}
}