【BZOJ 4887】【TJOI 2017】可乐

设f[i][j][1]表示第i秒停在j上没有爆炸的方案数,设f[i][j][0]表示第i秒停在j上的总方案数。
f[i][j][1]=f[i-1][j][1]+f[i-1][k][1]
f[i][j][0]=f[i-1][j][0]+f[i-1][j][1]+f[i-1][k][1]
然后我们发现这是一个一阶递推,所以直接矩阵转一转就好了!
PS:我可能对我那套矩阵理论有些。。不放心啊?我已开始傻逼地设了一个n行2列的矩阵,发现死活构造不出那个旋转因子(因为f[][][0]要同时去取f’[][][0]和f’[][][1])后来发现我真的傻,直接构造成一个2n行1列的矩阵不就好了。。。
注意一下初始化。

#include<cmath>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iomanip>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1000000000
#define mo 2017
#define N 200
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int n,m,i,j,t,ans;
int res[N],p[N],g[N][N],pp[N][N],x[N],y[N];
void mlt1()
{
	int i,j;
	fo(i,1,n) p[i] = res[i] , res[i] = 0;
	fo(i,1,n)
		fo(j,1,n)
			res[i]=(res[i]+1ll*g[i][j]*p[j]%mo)%mo;
}
void mlt2()
{
	int i,j,k;
	fo(i,1,n) fo(j,1,n) pp[i][j] = g[i][j] , g[i][j] = 0;
	fo(i,1,n)
		fo(j,1,n)
			fo(k,1,n)
				g[i][j]=(g[i][j]+1ll*pp[i][k]*pp[k][j]%mo)%mo;
}
int main()
{
	cin>>n>>m;
	fo(i,1,m) cin>>x[i]>>y[i];
	cin>>t;
	fo(i,1,n) g[i][i] = g[i][n+i] = 1;
	fo(i,n+1,n+n) g[i][i] = 1;
	fo(i,1,m) g[x[i]][n+y[i]] = g[y[i]][n+x[i]] = 1;
	fo(i,1,m) g[n+x[i]][n+y[i]] = g[n+y[i]][n+x[i]] = 1;
	res[1] = res[n+1] = 1; n = n * 2;
	while (t)
		{
			if (t&1) mlt1();
			mlt2(); t >>= 1;
		}
	fo(i,1,n/2) ans = (ans + res[i]) % mo;
	cout<<ans<<endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值