[题解] 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;
}
posted @ 2022-05-11 13:21  LegendStane  阅读(179)  评论(0)    收藏  举报