[BZOJ4887][TJOI2017]可乐(DP+矩阵快速幂)

题目描述

加里敦星球的人们特别喜欢喝可乐。因而,他们的敌对星球研发出了一个可乐机器人,并且放在了加里敦星球的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。

裸的矩阵加速DP

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 using namespace std;
 6 
 7 const int N=2000100,md=2017;
 8 struct mat{ int d[100][100]; mat(){ memset(d,0,sizeof(d)); } }a,b,c;
 9 int n,m,u,v,t,ans,cnt,h[N],nxt[N],to[N];
10 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
11 
12 void print(mat b){ rep(i,1,2*n){ rep(j,1,2*n) printf("%3d",b.d[i][j]); printf("
"); } }
13 
14 mat mul(mat a,mat b){
15     mat res;
16     rep(i,1,2*n) rep(j,1,2*n) rep(k,1,2*n) res.d[i][k]=(res.d[i][k]+a.d[i][j]*b.d[j][k]%md)%md;
17     return res;
18 }
19 
20 mat ksm(mat a,int b){
21     mat res;
22     rep(i,1,2*n) res.d[i][i]=1;
23     for (; b; a=mul(a,a),b>>=1)
24         if (b & 1) res=mul(res,a);
25     return res;
26 }
27 
28 int main(){
29     scanf("%d%d",&n,&m);
30     rep(i,1,m) scanf("%d%d",&u,&v),add(u,v),add(v,u);
31     scanf("%d",&t); a.d[1][1]=a.d[1][n+1]=1;
32     rep(i,1,n){
33         b.d[i][i]=b.d[i+n][i]=1;
34         for (int j=h[i]; j; j=nxt[j]) b.d[to[j]+n][i]=1;
35     }
36     rep(i,1,n){
37         b.d[i+n][i+n]=1;
38         for (int j=h[i]; j; j=nxt[j]) b.d[to[j]+n][i+n]=1;
39     }
40     c=mul(a,ksm(b,t));
41     rep(i,1,n) ans=(ans+c.d[1][i])%md;
42     printf("%d
",ans);
43     return 0;
44 }
原文地址:https://www.cnblogs.com/HocRiser/p/8457686.html