P3758 TJOI2017 可乐

记录边权的邻接矩阵

\(D_{i,j}=+\infty(i=j)||i与j间边权,i与j联通,+\infty(i,j不连通)\)

\(D_{(i,j)}^2=min_{i\le k\le n}D_{i,k}+D_{k,j}\)

\(D^K_{i,j}表示i到j经过k条边的最短路\)

记录连通性的矩阵意义等价

\(A^k_{i,j}表示由i到j经过k条边的方案数\)

P3758 TJOI2017 可乐

总方案数=\(t秒后处于各个位置的可能+所有已经爆炸的方案\)

在原先 n 个点的基础上加一个点 0,表示机器人自爆后的去处,每个点都向 0 连一条单向边

对于每个点可以添加一个自环,走这个自环就代表停在这里,那么每秒就都可以走一步

只需要建出邻接矩阵,然后矩阵快速幂求出点 1 到每一点的方案数,求和即可

扫描二维码关注公众号,回复: 11455199 查看本文章
#include<cstdio>
#include<cstring>
#define mod 2017
#define int long long
using namespace std;
int answ = 0,n,m;
struct mat
{
    int a[101][101];
    mat(){memset(a,0,sizeof(a));}
    void qwq(){for(int i=1;i<=n;i++)a[i][i]=1;}
}a,ans;
mat operator *(const mat &x,const mat &y)
    {
    mat z;
    for(int k=1;k<=n;++k)
    for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j)
    z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
    return z;
    }
signed main(){
	scanf("%lld%lld",&n,&m);
	n++;
	int x,y,t;
	for(int i = 1;i <= m;i++){
		scanf("%lld%lld",&x,&y);
		a.a[x][y] = 1; a.a[y][x] = 1;
	}
	for(int i=1;i<=n;i++)a.a[i][n]=1,a.a[i][i]=1;
	ans.qwq();
	scanf("%lld",&t);
	while(t){
		if(t & 1) ans = ans * a;
		t >>=1;
		a = a * a;
	}
	for(int i = 1;i <= n;i++)
	answ = (ans.a[1][i] + answ) % mod;
	printf("%lld",answ);
}

猜你喜欢

转载自www.cnblogs.com/shikeyu/p/13387080.html