[TJOI2017]可乐

题目大意:
  一个$n(n\le30)$个点$m(m\le100)$条边的无向图,每次可以选择移动到相邻点、原地不动或原地自爆。一开始在编号为$1$的点,问$t(t\le10^6)$秒后有多少种可能的行为方案?

思路:
  新建结点编号$0$表示原地自爆,则在原图基础上对于每个点加上自环和通向$0$的有向边,用邻接矩阵$T$表示。用矩阵$F$记录方案数,其中$F_{0,i}$表示最后一步在$i$处的方案数,初始状态$F_{0,1}=1$。用矩阵快速幂算出$F'=F\times T^t$,答案即为$\sum F'_{0,i}$。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<cstring>
 4 inline int getint() {
 5     register char ch;
 6     while(!isdigit(ch=getchar()));
 7     register int x=ch^'0';
 8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
 9     return x;
10 }
11 const int N=31,mod=2017;
12 int tmp[N][N];
13 struct Matrix {
14     int n,m,val[N][N];
15     void resize(const int &n,const int &m) {
16         this->n=n;
17         this->m=m;
18     }
19     Matrix &operator *= (const Matrix another) {
20         for(register int i=0;i<n;i++) {
21             for(register int j=0;j<another.m;j++) {
22                 tmp[i][j]=0;
23                 for(register int k=0;k<m;k++) {
24                     (tmp[i][j]+=val[i][k]*another.val[k][j]%mod)%=mod;
25                 }
26             }
27         }
28         memcpy(val,tmp,sizeof val);
29         return *this;
30     }
31 };
32 Matrix f,t;
33 int main() {
34     const int n=getint(),m=getint();
35     f.resize(1,n+1);
36     t.resize(n+1,n+1);
37     for(register int i=0;i<=n;i++) {
38         t.val[i][i]=t.val[i][0]=1;
39     }
40     for(register int i=0;i<m;i++) {
41         const int u=getint(),v=getint();
42         t.val[u][v]=t.val[v][u]=1;
43     }
44     f.val[0][1]=1;
45     for(register int k=getint();k;k>>=1,t*=t) {
46         if(k&1) f*=t;
47     }
48     int ans=0;
49     for(register int i=0;i<=n;i++) {
50         (ans+=f.val[0][i])%=mod;
51     }
52     printf("%d\n",ans);
53     return 0;
54 }

 

posted @ 2018-04-10 14:55  skylee03  阅读(105)  评论(0编辑  收藏  举报