zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    windows7上使用docker容器
    centos7 docker镜像加速器配置
    用列表生成器打印九九乘法表
    -bash: wget: command not found的两种解决方法
    centos7 Dockerfile安装nginx
    centos6.5关闭防火墙命令
    centos7开机启动tomcat7
    centos7安装tomcat7
    CentOS7防火墙firewalld
    poj_3662 最小化第k大的值
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1898.html
Copyright © 2011-2022 走看看