[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:
3 2 1 2 2 3 2
输出样例#1:
8
说明
【样例解释】
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^9。
设f[i][j][0/1]表示i时刻,j地,是否爆炸
f[i][j][0]=∑f[i-1][k][0]+f[i-1][j][0]
f[i][j][1]=f[i-1][j][1]+f[i-1][j][0]
但直接dp显然超时,考虑用矩阵
(s0,s1,s2,s3.....)
s0为已爆炸的方案,s1表示到1的方案
转移:
s0=s0'+s1'+s2'......+sn'
s1=s1'+sk'
.....
所以可以写成一个(n+1)*(n+1)的矩阵
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 struct Matrix 7 { 8 long long a[101][101]; 9 }Mat,pre,ans; 10 int n,m,t; 11 long long s; 12 Matrix operator *(const Matrix &x,const Matrix &y) 13 { 14 Matrix res; 15 int i,j,k; 16 memset(res.a,0,sizeof(res.a)); 17 for (i=0;i<=n;i++) 18 { 19 for (j=0;j<=n;j++) 20 { 21 for (k=0;k<=n;k++) 22 res.a[i][j]+=x.a[i][k]*y.a[k][j]; 23 res.a[i][j]%=2017; 24 } 25 } 26 return res; 27 } 28 void qpow(int x) 29 {int i; 30 for (i=0;i<=n;i++) 31 ans.a[i][i]=1; 32 while (x) 33 { 34 if (x&1) ans=ans*Mat; 35 Mat=Mat*Mat; 36 x/=2; 37 } 38 } 39 int main() 40 {int x,y,i; 41 cin>>n>>m; 42 for (i=1;i<=m;i++) 43 { 44 scanf("%d%d",&x,&y); 45 Mat.a[x][y]=1; 46 Mat.a[y][x]=1; 47 } 48 cin>>t; 49 for (i=1;i<=n;i++) 50 Mat.a[i][i]=1; 51 for (i=0;i<=n;i++) 52 Mat.a[i][0]=1; 53 memset(pre.a,0,sizeof(pre.a)); 54 qpow(t); 55 pre.a[0][1]=1; 56 ans=pre*ans; 57 for (i=0;i<=n;i++) 58 s+=ans.a[0][i],s%=2017; 59 cout<<s; 60 }