SDOI的好题,今天听豪爷讲课的时候第一眼没有想出来,一般对10^9比较敏感,就能想到矩乘,但是一看2^30就开始想什么倍增了。
f[i][2][k]表示刚走完第i条边正着走还是倒着走,走过k距离的方案数。
转移是:f[i][0][k]-->f[j][0][k+1] i.y==j.x
-->f[j][1][k+1] i.y==j.y
f[i][1][k]-->f[j][0][k+1] i.x==j.x
-->f[j][1][k+1] i.x==j.y
然后矩乘就好了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define mod 45989
using namespace std;
struct matrix
{
int x,y;
int a[121][121];
matrix operator* (matrix b)
{
matrix ans;
memset(ans.a,0,sizeof(ans.a));
ans.x=x;ans.y=b.y;
for (int i=1;i<=ans.x;i++)
for (int j=1;j<=ans.y;j++)
for (int k=1;k<=y;k++)
ans.a[i][j]=(ans.a[i][j]+a[i][k]*b.a[k][j])%mod;
return ans;
}
};
int x[61],y[61];
int n,m,k,s,t;
int main()
{
scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
for (int i=1;i<=m;i++)
scanf("%d%d",&x[i],&y[i]);
matrix a,b;
a.x=1,a.y=2*m;
memset(a.a,0,sizeof(a.a));
b.x=2*m;b.y=2*m;
memset(b.a,0,sizeof(b.a));
for (int i=1;i<=m;i++)
{
if (x[i]==s) a.a[1][i]=1;
if (y[i]==s) a.a[1][i+m]=1;
}
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++)
{
if (i==j) continue;
if (y[i]==x[j]) b.a[i][j]++;
if (y[i]==y[j]) b.a[i][j+m]++;
if (x[i]==x[j]) b.a[i+m][j]++;
if (x[i]==y[j]) b.a[i+m][j+m]++;
}
matrix ans;
memset(ans.a,0,sizeof(ans.a));
ans.x=2*m;ans.y=2*m;
for (int i=1;i<=ans.x;i++) ans.a[i][i]=1;
k--;
while (k>0)
{
if (k&1) ans=ans*b;
b=b*b;
k>>=1;
}
ans=a*ans;
int sum=0;
for (int i=1;i<=m;i++)
{
if (x[i]==t) sum=(sum+ans.a[1][i+m])%mod;
if (y[i]==t) sum=(sum+ans.a[1][i])%mod;
}
printf("%d\n",sum);
return 0;
}