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 ightarrow 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;
}
原文地址:https://www.cnblogs.com/five20/p/9852054.html