[题解] Atcoder ABC 213 H Stroll DP,分治FFT
题目
令\(dp_{i,j}\)表示从点1到达点i,路径长度为j的方案数。转移为\(dp_{i,j}=\sum_{(i,v,w)\in E}dp_{v,j-w}p_{i,v,w}\)。
显然只能从长度小的转移到长度大的,而且转移是一个自己和自己卷积的形式。考虑分治FFT,当分治到\((l,r)\)时,考虑\(dp_{i,t1} \to dp_{j,t2}(l \leq t1 \leq mid,mid < t2 \leq r)\)的转移。枚举i和j(i,j之间存在边),把\(dp_{i,t1}(l \leq t1 \leq mid)\)和\(p_{i,j,k}(0<k < r-l+1)\)做一次卷积就可以完成一次转移。总时间复杂度\(O(mTlog^2T)\)。
点击查看代码
#include <bits/stdc++.h>
#include <atcoder/all>
#define rep(i,n) for(int i=0;i<n;++i)
#define repn(i,n) for(int i=1;i<=n;++i)
#define LL long long
#define pii pair <int,int>
#define fi first
#define se second
#define mpr make_pair
#define pb push_back
using namespace std;
using mint=atcoder::modint998244353;
const LL MOD=998244353;
LL n,m,t,p[60][40010],dp[60][40010];
vector <pii> g[20];
vector <mint> A,B,C;
void solve(LL lb,LL ub)
{
if(lb==ub)
{
if(lb==0) dp[1][0]=1;
return;
}
LL mid=(lb+ub)/2;
solve(lb,mid);
repn(i,n) rep(j,g[i].size())
{
LL u=i,v=g[i][j].fi,eid=g[i][j].se;
A.clear();B.clear();
for(int ii=lb;ii<=mid;++ii) A.pb(dp[u][ii]);
B.pb(0);
repn(ii,ub-lb+1) B.pb(p[eid][ii]);
C=atcoder::convolution(A,B);
for(int ii=mid+1;ii<=ub;++ii) (dp[v][ii]+=C[ii-lb].val())%=MOD;
}
solve(mid+1,ub);
}
int main()
{
cin>>n>>m>>t;
LL x,y;
rep(i,m)
{
scanf("%lld%lld",&x,&y);
g[x].pb(mpr(y,i));g[y].pb(mpr(x,i));
repn(j,t) scanf("%lld",&p[i][j]);
}
solve(0,t);
cout<<dp[1][t]<<endl;
return 0;
}