洛谷P3758 [TJOI2017]可乐
原题链接:洛谷P3758 [TJOI2017]可乐
题目描述
加里敦星球的人们特别喜欢喝可乐。因而,他们的敌对星球研发出了一个可乐机器人,并且放在了加里敦星球的1号城市上。这个可乐机器人有三种行为: 停在原地,去下一个相邻的城市,自爆。它每一秒都会随机触发一种行为。现 在给加里敦星球城市图,在第0秒时可乐机器人在1号城市,问经过了t秒,可乐机器人的行为方案数是多少?
输入输出格式
输入格式:
第一行输入两个正整数况N,M,N表示城市个数,M表示道路个数。(1 <= N <=30,0 < M < 100)
接下来M行输入u,v,表示u,v之间有一条道路。(1<=u,v <= n)保证两座城市之间只有一条路相连。
最后输入入时间t
输出格式:
输出可乐机器人的行为方案数,答案可能很大,请输出对2017取模后的结果。
输入输出样例
说明
【样例解释】
1 ->爆炸
1 -> 1 ->爆炸
1 -> 2 ->爆炸
1 -> 1 -> 1
1 -> 1 -> 2
1 -> 2 -> 1
1 -> 2 -> 2
1 -> 2 -> 3
【数据范围】
对于20%的pn,有1 < t ≤ 1000
对于100%的pn,有1 < t ≤ 10^6。
题解
题意:给定一个无向图,一个机器人每一秒可以留在原地,自爆或走一步,求在t秒内机器人所有行动的可能性
算法:邻接矩阵+矩阵乘法
建模:图直接建,留在原地则让每一个点向自己连边,自爆则设一个点为爆炸,每一个点向爆炸点连边(爆炸点向自己连边)
base.m[0][0]=1; for(int i=1;i<=L;i++){ base.m[i][i]=base.m[i][0]=1; } for(int i=1;i<=M;i++){ int ii,jj; scanf("%d%d",&ii,&jj); base.m[ii][jj]=base.m[jj][ii]=1; }
设f[i][j][t]为从i到j进过t秒的行动方案数,类似于Floyd的转移,有f[i][j][t1+t2]=∑f[i][k][t1]+f[k][j][t1]
设f[][][x]为f[x],故矩阵f[t1+t2]=f[t1]*f[t2],即可用矩阵乘法,而此题答案就为f[1]t,矩阵快速幂即可
矩阵乘法及快速幂:
inline matrix operator*(matrix x,matrix y){ matrix ret; for(int i=0;i<=L;i++){ for(int j=0;j<=L;j++) for(int k=0;k<=L;k++) ret.m[i][j]=(ret.m[i][j]+x.m[i][k]*y.m[k][j])%MOD; } return ret; } inline matrix operator^(matrix x,int p){ matrix ret; ret.build(); while(p){ if(p&1) ret=ret*x; x=x*x; p>>=1; } return ret; }
核心代码:
ans=(base^T); LL sum=0; for(int i=0;i<=L;i++){ sum=(sum+ans.m[1][i])%MOD; }
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int MOD=2017,MAXL=32; 5 int L,M,T; 6 struct matrix{ 7 LL m[MAXL][MAXL]; 8 matrix(){ 9 memset(m,0,sizeof(m)); 10 } 11 inline void build(){ 12 memset(m,0,sizeof(m)); 13 for(int i=0;i<=L;i++) 14 m[i][i]=1; 15 } 16 inline void print(){ 17 for(int i=0;i<=L;i++,putchar('\n')) 18 for(int j=0;j<=L;j++) 19 printf("%lld ",m[i][j]); 20 putchar('\n'); 21 } 22 }; 23 inline matrix operator*(matrix x,matrix y){ 24 matrix ret; 25 for(int i=0;i<=L;i++){ 26 for(int j=0;j<=L;j++) 27 for(int k=0;k<=L;k++) 28 ret.m[i][j]=(ret.m[i][j]+x.m[i][k]*y.m[k][j])%MOD; 29 } 30 return ret; 31 } 32 inline matrix operator^(matrix x,int p){ 33 matrix ret; 34 ret.build(); 35 while(p){ 36 if(p&1) 37 ret=ret*x; 38 x=x*x; 39 p>>=1; 40 } 41 return ret; 42 } 43 int main(){ 44 scanf("%d%d",&L,&M); 45 matrix ans,base; 46 ans.build(); 47 base.m[0][0]=1; 48 for(int i=1;i<=L;i++){ 49 base.m[i][i]=base.m[i][0]=1; 50 } 51 for(int i=1;i<=M;i++){ 52 int ii,jj; 53 scanf("%d%d",&ii,&jj); 54 base.m[ii][jj]=base.m[jj][ii]=1; 55 } 56 scanf("%d",&T); 57 ans=(base^T); 58 LL sum=0; 59 for(int i=0;i<=L;i++){ 60 sum=(sum+ans.m[1][i])%MOD; 61 } 62 printf("%lld",sum); 63 return 0; 64 }