正题
题目链接:https://jzoj.net/senior/#main/show/3847
题目大意
nnn个点mmm条边,第iii个点要求hih_ihi时才可以到达。求经过ttt时从点1到点nnn的方案数。
解题思路
因为hih_ihi较小,设zi,kz_{i,k}zi,k表示iii时到kkk的方案数,转移到最大的hih_ihi后就用矩阵乘法处理。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=75,XJQ=10086;
struct matrix{ll a[N][N];
}f;
ll n,m,t,h[N],z[N][N],ans,maxs;
matrix operator*(matrix &a,matrix &b){matrix c;memset(c.a,0,sizeof(c.a));for(ll i=1;i<=n;i++)for(ll j=1;j<=n;j++)for(ll k=1;k<=n;k++)(c.a[i][j]+=a.a[i][k]*b.a[k][j]%XJQ)%=XJQ;return c;
}
matrix ksm(matrix f,ll b){matrix ans;memset(ans.a,0,sizeof(ans.a));for(ll i=1;i<=n;i++)ans.a[i][i]=1;while(b){if(b&1) ans=ans*f;f=f*f;b>>=1;}return ans;
}
int main()
{scanf("%lld%lld%lld",&n,&m,&t);for(ll i=1;i<=n;i++){scanf("%lld",&h[i]);maxs=max(maxs,h[i]);f.a[i][i]++;}for(ll i=1;i<=m;i++){ll x,y;scanf("%lld%lld",&x,&y);f.a[x][y]++;}z[0][1]=1;maxs=min(t,maxs);for(ll i=1;i<=maxs;i++){for(ll x=1;x<=n;x++)for(ll y=1;y<=n;y++)if(f.a[x][y]&&h[y]<=i)z[i][y]=(z[i][y]+z[i-1][x]*f.a[x][y]%XJQ)%XJQ;}f=ksm(f,t-maxs);for(ll x=1;x<=n;x++)for(ll y=1;y<=n;y++)(z[maxs+1][y]+=z[maxs][x]*f.a[x][y]%XJQ)%=XJQ;printf("%lld",z[maxs+1][n]);
}