BZOJ 1875: [SDOI2009]HH去散步
1875: [SDOI2009]HH去散步
Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 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
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
分析:
不错的转化...
我们第一想法大概就是矩阵优化DP,但是发现貌似过不了,所以我们可以考虑用边作为状态来DP...
$f[i][j]$代表从边$i$走向边$j$的方案数...
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步