P3758 [TJOI2017]可乐

原题链接
考察:矩阵快速幂
思路:
  想了dp转移方程,看了题解发现没有这么复杂,利用邻接矩阵的性质就行了,参考Floyd算法,外层每循环一次,相当于经过了一条边,也是转移到了一个新的状态.
  把停留看成自环,城市之间的道路就等同于邻接矩阵的原本意义,但是爆炸就比较难处理.大佬的思路是建立虚点,该点只有入度没有出度.那么每进行一次floyd就相当于进行状态转移.但是t太大了,所以进行矩阵加速.
  但是注意如果虚点0-->0 的权值为0的话,就会发现爆栈的方案数无法传递,所以赋值1.

Code

#include <iostream> 
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 35,M = 2017;
int n,m,T,g[N][N],f[N]; 
void mul(int f[],int a[][N])
{
	int res[N] = {0};
	for(int i=0;i<N;i++)
	  for(int j=0;j<N;j++)
	   res[i] = (res[i]+(LL)f[j]*a[j][i])%M;
	memcpy(f,res,sizeof res);
}
void mul(int a[][N])
{
	int res[N][N] = {0};
	for(int i=0;i<N;i++)
	  for(int j=0;j<N;j++)
	    for(int k=0;k<N;k++)
	     res[i][j] = (res[i][j]+(LL)a[i][k]*a[k][j])%M;
	memcpy(a,res,sizeof res);
}
int main()
{
	scanf("%d%d",&n,&m);//爆炸的方案数需要传递 
	for(int i=0;i<=n;i++) g[i][0] = g[i][i] =1;
	while(m--) 
	{
		int x,y;
		scanf("%d%d",&x,&y);
		g[x][y] = g[y][x] = 1;
	}
	f[1] = 1;
	scanf("%d",&T);
	while(T)
	{
		if(T&1) mul(f,g);
		mul(g);
		T>>=1;
	}
	int ans = 0;
	for(int i=0;i<=n;i++) ans+=f[i],ans%=M;
	printf("%d\n",ans);
	return 0;
}
posted @ 2021-06-10 14:33  acmloser  阅读(37)  评论(0编辑  收藏  举报