BZOJ 1875: [SDOI2009]HH去散步

1875: [SDOI2009]HH去散步

Time Limit: 20 Sec  Memory Limit: 64 MB
Submit: 1638  Solved: 791
[Submit][Status][Discuss]

Description

HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径

Input

第一行:五个整数N,M,t,A,B。其中N表示学校里的路口的个数,M表示学校里的 路的条数,t表示HH想要散步的距离,A表示散步的出发点,而B则表示散步的终点。 接下来M行,每行一组Ai,Bi,表示从路口Ai到路口Bi有一条路。数据保证Ai = Bi,但 不保证任意两个路口之间至多只有一条路相连接。 路口编号从0到N − 1。 同一行内所有数据均由一个空格隔开,行首行尾没有多余空格。没有多余空行。 答案模45989。

Output

一行,表示答案。

Sample Input

4 5 3 0 0
0 1
0 2
0 3
2 1
3 2

Sample Output

4

HINT

对于30%的数据,N ≤ 4,M ≤ 10,t ≤ 10。 对于100%的数据,N ≤ 20,M ≤ 60,t ≤ 2^30,0 ≤ A,B

Source

Day1

分析:

不错的转化...

我们第一想法大概就是矩阵优化DP,但是发现貌似过不了,所以我们可以考虑用边作为状态来DP...

$f[i][j]$代表从边$i$走向边$j$的方案数...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=120+5,mod=45989;

int n,m,t,A,B,ans,cnt,hd[maxn],to[maxn],pre[maxn],nxt[maxn];

struct M{
	
	int a[maxn][maxn];
	
	inline void init(void){
		memset(a,0,sizeof(a));
	}
	
	inline void initone(void){
		memset(a,0,sizeof(a));
		for(int i=0;i<cnt;i++) a[i][i]=1;
	}
	
	friend M operator * (M x,M y){
		M res;res.init();
		for(int i=0;i<cnt;i++)
			for(int j=0;j<cnt;j++)
				for(int k=0;k<cnt;k++)
					(res.a[i][j]+=1LL*x.a[i][k]*y.a[k][j]%mod)%=mod;
		return res;
	}
	
}pri;

inline M power(M x,int y){
	M res;res.initone();
	while(y){
		if(y&1)
			res=res*x;
		x=x*x,y>>=1;
	}
	return res;
}

inline void add(int x,int y){
	to[cnt]=y;pre[cnt]=x;nxt[cnt]=hd[x];hd[x]=cnt++;
}

signed main(void){
	scanf("%d%d%d%d%d",&n,&m,&t,&A,&B);
	cnt=0;pri.init();memset(hd,-1,sizeof(hd));
	if(t==0) return puts(A==B?"1":"0"),0; 
	for(int i=1,x,y;i<=m;i++)
		scanf("%d%d",&x,&y),add(x,y),add(y,x);
	for(int i=0;i<cnt;i++)
		for(int j=0;j<cnt;j++)
			if(i!=j&&(i^j)!=1&&to[i]==pre[j])
				pri.a[i][j]++;
	pri=power(pri,t-1);
	for(int i=hd[A];i!=-1;i=nxt[i])
		for(int j=hd[B];j!=-1;j=nxt[j])
			ans=(ans+pri.a[i][j^1])%mod;
	printf("%d\n",ans);
	return 0;
}	

  


By NeighThorn

posted @ 2017-04-01 15:56  NeighThorn  阅读(156)  评论(0编辑  收藏  举报