BZOJ1898 [Zjoi2005]Swamp 沼泽鳄鱼 矩阵

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1898


题意概括

  有一个无向图。

  其中,有许多条鱼在以循环的规律出现,比如循环在1,2,3这些点出现。循环节长度=2,3,4 。

  现在,你要从A花费K个单位时间到达B,中途不能和鱼相碰,问有多少方案。

  (每个单位时间,鱼从当前的点走向循环中的下一个点)。

  n<=50,K<=2000000000


题解

  注意到循环节长度为2或3或4.

  如果不考虑鱼,那么就是简单的矩阵优化路径统计。可以看这个

  现在考虑鱼。

  那么就是对于某一时刻,某些鱼所在的位置的路径数都要清0 。

  我们发现循环接长度很小。最小公倍数为12!

  所以我们可以12个12个来。

  对于其中12个,我们大力dp。

  然后对于K/12,我们可以用矩阵快速幂解决。对于剩余的K%12,我们也可以再乘上一个矩阵。

  然后就搞定了。


代码

#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N=50+5,M=N*N/2,F=20+5,T=5,LCM=12,mod=10000;
int n,m,st,en,K,ways[LCM+3][N][N];
bool loc[N][LCM+3],g[N][N];
struct Mat{
	int v[N][N];
	void set(int x){
		memset(v,0,sizeof v);
		if (x!=1)
			return;
		for (int i=1;i<=n;i++)
			v[i][i]=1;
	}
	Mat operator * (Mat x){
		Mat ans;
		ans.set(0);
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				for (int k=1;k<=n;k++)
					ans.v[i][j]=(ans.v[i][j]+v[i][k]*x.v[k][j])%mod;
		return ans;
	}
}M0,M1,M2,M3;
Mat MatPow(Mat x,int y){
	Mat ans,now=x;
	ans.set(1);
	while (y){
		if (y&1)
			ans=ans*now;
		now=now*now;
		y>>=1;
	}
	return ans;
}
void Get_Loc(){
	int Nfish,t,a[5];
	scanf("%d",&Nfish);
	memset(loc,0,sizeof loc);
	while (Nfish--){
		scanf("%d",&t);
		for (int i=1;i<=t;i++)
			scanf("%d",&a[i]),a[i]++;
		for (int i=1;i<=12;i++)
			loc[a[i%t+1]][i]=1;
	}
}
int main(){
	scanf("%d%d%d%d%d",&n,&m,&st,&en,&K),st++,en++;
	memset(g,0,sizeof g);
	for (int i=1,a,b;i<=m;i++){
		scanf("%d%d",&a,&b),a++,b++;
		g[a][b]=g[b][a]=1;
	}
	Get_Loc();
	for (int i=1;i<=n;i++)
		ways[0][i][i]=1;
	for (int t=1;t<=12;t++){
		for (int i=1;i<=n;i++)
			for (int j=1;j<=n;j++)
				for (int k=1;k<=n;k++)
					if (g[j][k])
						ways[t][i][k]=(ways[t][i][k]+ways[t-1][i][j])%mod;
		for (int i=1;i<=n;i++)
			if (loc[i][t])
				for (int j=1;j<=n;j++)
					ways[t][j][i]=0;
	}
	M0.set(0),M2.set(0);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			M0.v[i][j]=ways[12][i][j],M2.v[i][j]=ways[K%12][i][j];
	M1=MatPow(M0,K/12);
	M3=M1*M2;
	printf("%d",M3.v[st][en]);
	return 0;
}

  

posted @ 2017-09-16 22:33  zzd233  阅读(235)  评论(0编辑  收藏  举报