[ZJOI2005] 沼泽鳄鱼&[TJOI2017] 可乐

沼泽鳄鱼
肥宅快乐水(滑稽
这两道题其实差不多
肥宅快乐水简单一些,先说他

题目大意就是给你一张图,每个时间段你有几个抉择:
1.停留
2.走一步
3.自爆(emmmmm)

问经过k个时间的方案数,n特别的小,k特别的大

通过这道题,我们引入一个东西,叫做邻接矩阵乘法
就是一个图,走k步的方案数,等于他的邻接矩阵的n次方!
为什么呢?
比如说我们设这个邻接矩阵是 G G
那么
G 2 [ i ] [ j ] = k = 1 n G [ i ] [ k ] G [ k ] [ j ] G^2[i][j]=\sum_{k=1}^n G[i][k]*G[k][j]
通过乘法原理和加法原理,我们知道,这就是 i i j j 走两步的方案数(也可以想象成 f l o y d floyd
G 3 [ i ] [ j ] = k = 1 n l = 1 n G [ i ] [ k ] G [ k ] [ l ] G [ l ] [ j ] G^3[i][j]=\sum_{k=1}^n\sum_{l=1}^n G[i][k]*G[k][l]*G[l][j]
本质上还是 i i j j 走三次的方案数
我们就可以把它推到任意正整数次幂QAQ

知道了这个这道题就很好做了
先处理好初始邻接矩阵
对于停留,自己给自己连一条边
对于走一步,正常邻接矩阵
对于自爆问题,我们只需要把所有的点都连向一个节点 n + 1 n+1 并且不给他连出边就可以了

那么答案就是 i = 1 n + 1 G k [ 1 ] [ i ] \sum_{i=1}^{n+1}G^k[1][i]

代码:

# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;
const int N=35;
const int mod=2017;
const double eps=1e-7;
template <typename T> void read(T &x){
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

int n,m,t;

struct matrix{
	int x;
	int a[N][N];
	matrix(){x=0,memset(a,0,sizeof(a));}
	matrix operator * (const matrix &y)const{
		matrix res;
		res.x=x;
		Rep(i,1,x)
			Rep(j,1,x)
				Rep(k,1,x)
					res.a[i][j]=(res.a[i][j]+a[i][k]*y.a[k][j])%mod;
		return res;
	}
	void build(int sz){
		x=sz;
		Rep(i,1,x)a[i][i]=1;	
	}
	void print(){
		Rep(i,1,x)
			Rep(j,1,x)
				printf("%d%c",a[i][j],j==x?'\n':' ');	
	}
}a;
int ans;

matrix Qpow(matrix base,int ind){
	matrix res;
	res.build(n+1);
//	res.print();
	while(ind){
		if(ind&1)res=res*base;
		base=base*base;
		ind>>=1;
	}
	return res;
}

int main()
{
	read(n),read(m);
	a.build(n+1);
	Rep(i,1,m){
		int x,y;
		read(x),read(y);
		a.a[x][y]=a.a[y][x]=1;
	}
	Rep(i,1,n)a.a[i][n+1]=1;
	read(t);
	a=Qpow(a,t);
//	a.print();
	Rep(j,1,n+1)
		ans=(ans+a.a[1][j]+mod)%mod;
	printf("%d\n",ans);
	return 0;
}

沼泽鳄鱼那道题其实和可乐差不多,唯一有区别的地方时在有些时候有些地方不能走

这个怎么处理呢?
我们观察发现,那些食人鱼的游动的周期是2,3,4,他们的lcm是12,这样我们可以构建12个状态,然后再做矩阵乘法就可以了

# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;
const int N=105;
const int inf=0x7fffffff;
const int mod=10000;
template <typename T> void read(T &x){
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

int n,m,K,nf;//let you down
int s,t;
bool cyl[N][15];
bool beg[N][N];

struct matrix{
	int a[N][N];
	int x,y;
	matrix(){memset(a,0,sizeof(a));}
	matrix operator * (const matrix &xx)	const{
		matrix res;
		res.x=x,res.y=xx.y;
		Rep(i,1,x)
			Rep(j,1,xx.y)
				Rep(k,1,y)
					res.a[i][j]=(res.a[i][j]+a[i][k]*xx.a[k][j])%mod;
		return res;
	}
	void build(int sz){
		x=sz,y=sz;
		Rep(i,1,x)
			a[i][i]=1;	
	}
	void print(){
		Rep(i,1,x){
			Rep(j,1,y)
				printf("%d ",a[i][j]);
			puts("");
		}
	}
}ans,a[N],prod;

matrix Qpow(matrix base,int ind){
	matrix res;
	res.build(n);
	while(ind){
		if(ind&1)res=res*base;
		base=base*base;
		ind>>=1;
	}
	return res;
}

int main()
{
	read(n),read(m),read(s),read(t),read(K);
	Rep(i,1,m){
		int x,y;
		read(x),read(y);
		x++,y++;
		beg[x][y]=beg[y][x]=true; 
	}
	read(nf);
	Rep(i,1,nf){
		int trn,x;
		read(trn);
		Rep(j,0,trn-1){
			read(x);
			x++;
			for(int k=j;k<12;k+=trn)
				cyl[x][k]=true; 
		}
	}
	Rep(which,0,11)
		Rep(i,1,n)
			Rep(j,1,n)
				if(beg[i][j]&&!cyl[j][which])
					a[which].a[i][j]=1;
	Rep(i,0,11)a[i].x=a[i].y=n;
	prod.build(n);
	int times=K/12,add=K%12;
	Rep(i,1,11)prod=prod*a[i];
	prod=prod*a[0];
	ans=Qpow(prod,times);
	Rep(i,1,add)ans=ans*a[i];
	printf("%d\n",ans.a[s+1][t+1]);
	return 0;
}
发布了45 篇原创文章 · 获赞 52 · 访问量 9641

猜你喜欢

转载自blog.csdn.net/devout_/article/details/104236351
今日推荐