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:
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^6。
Solution:
本题矩阵快速幂。
一个显然的dp思路就是由当前点的方案数向所到点转移,那么我们可以构建一个邻接矩阵:
1、对于边$u\rightarrow v$,令$w[u][v]=w[v][u]=1$。
2、对于停在原地,令$w[u][u]=1$。
3、对于自爆,构建不和其他点联通的虚点$0$,建单向边$w[u][0]=1$。
然后只需要跑下矩阵快速幂就好了。
代码:
/*Code by 520 -- 10.11*/ #include<bits/stdc++.h> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) using namespace std; const int N=35,mod=2017; struct matrix{ int a[N][N],r,c; il void clr(){memset(a,0,sizeof(a));} }ans,tp; int tot,n,m,t; il matrix mul(matrix x,matrix y){ matrix tp; tp.clr(); tp.r=x.r,tp.c=y.c; For(i,0,x.r) For(j,0,y.c) For(k,0,x.c) tp.a[i][j]=(tp.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod; return tp; } int main(){ scanf("%d%d",&n,&m); int u,v; ans.r=0,ans.c=n; tp.r=n,tp.c=n; For(i,1,m) scanf("%d%d",&u,&v),tp.a[u][v]=tp.a[v][u]=1; For(i,0,n) tp.a[i][0]=1,tp.a[i][i]=1; ans.a[0][1]=1; scanf("%d",&t); while(t){ if(t&1) ans=mul(ans,tp); t>>=1,tp=mul(tp,tp); } For(i,0,n) tot=(tot+ans.a[0][i])%mod; cout<<tot; return 0; }
PS:~蒟蒻写博客不易,转载请注明出处,万分感谢!~