您的位置:首页 > 其它

bzoj 1875 HH去散步

2015-11-16 10:38 162 查看
看到1e9的数据范围,不难想到是矩乘,但是按照边去设状态确实很神。然后f[i][j]表示第j-1步走边j的方案数,我一直没看出来要减一。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>

#define md 45989
#define ll long long
#define inf (int) 1e9
#define eps 1e-8
#define N 45
#define M 150
using namespace std;
struct ju { int a[M][M],x,y;} a,ans;
struct yts{ int x,t,ne;} e[M];
int num=1;
int v
;
void put(int x,int y)
{
	num++; e[num].x=x; e[num].t=y;
	e[num].ne=v[x]; v[x]=num;
}
ju operator * (ju a,ju b)
{
	ju ans;
	memset(ans.a,0,sizeof(ans.a));
	for (int i=1;i<=a.x;i++)
	  for (int j=1;j<=b.y;j++)
	    for (int k=1;k<=a.y;k++)
	      ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%md;
	ans.x=a.x; ans.y=a.y;
	return ans;
}
void outit(ju a)
{
	for (int i=1;i<=num;i++)
	{
		for (int j=1;j<=num;j++) 
		  printf("%d ",a.a[i][j]);
		printf("\n");
	}
	printf("\n");
}
int main()
{
	int n,m,K,A,B;
	scanf("%d%d%d%d%d",&n,&m,&K,&A,&B); K--;
	for (int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		put(x,y); put(y,x);
	}
	for (int i=2;i<=num;i++)
	{
		int x=e[i].t;
		for (int j=v[x];j;j=e[j].ne)
		{
			if (j!=(i^1)) a.a[i][j]=1;
		}
	}
	a.x=a.y=num; //outit(a);
	for (int i=1;i<=num;i++) ans.a[i][i]=1; ans.x=ans.y=num;
	while (K)
	{
		if (K&1) ans=ans*a;
		K>>=1; a=a*a;
	}
	//outit(ans);
	for (int i=2;i<=num;i++)
	  if (e[i].x==A) a.a[1][i]=1; else a.a[1][i]=0;
	//outit(a);
	a.x=1; a.y=num;
	a=a*ans;
	//outit(a); 
	ll sum=0;
	for (int i=2;i<=num;i++)
	  if (e[i].t==B) (sum+=a.a[1][i])%=md;
	printf("%d\n",sum);
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: