Harry And Math Teacher

六月ゝ 毕业季﹏ 提交于 2020-01-13 03:56:53

一、题目

点此看题
题目描述
nn层楼,每层有两个门(编号为1/21/2),ii层到i+1i+1的门两两相通,有下列操作:

  • ii层到i+1i+1层的x,yx,y两个门的状态改变(联通变成不同,不同变成联通)
  • 询问xxyy的方案数,可以从xx任意门入,yy任意门出。

数据范围
多组数据,1n,m500001\leq n,m\leq 50000

二、解法

考虑dp[i][0/1]dp[i][0/1]也就是到了ii层的1/21/2号门的方案数,pd[i][j]pd[i][j]表示i,ji,j号门之间有无通路,有下列转移:
dp[i][0]=pd[0][0]×dp[i1][0]+pd[1][0]×dp[i1][1]dp[i][0]=pd[0][0]\times dp[i-1][0]+pd[1][0]\times dp[i-1][1]dp[i][1]=pd[0][1]+dp[i1][0]+pd[1][1]×dp[i1][1]dp[i][1]=pd[0][1]+dp[i-1][0]+pd[1][1]\times dp[i-1][1]上述转移很像矩阵乘法的递推,我们可以把[x,y1][x,y-1]之间的矩阵乘起来,然后对系数求和就是方案数。

然后发现可以用线段树优化,第一个操作就是一个单点修改,第二个操作就是一个区间查询,时间复杂度O(nlogn)O(n\log n)

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define LL long long
const LL MOD = 1e9+7;
const LL MAXN = 100005;
LL read()
{
	LL x=0,flag=1;char c;
	while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
	while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*flag;
}
int n,m;LL x,y;
struct Matrix
{
	LL a[3][3];
	Matrix() {memset(a,0,sizeof a);}
	Matrix operator * (const Matrix &B)
	{
		Matrix R;
		for(LL i=1;i<=2;i++)
			for(LL j=1;j<=2;j++)
				for(LL k=1;k<=2;k++)
					R.a[i][k]=(R.a[i][k]+a[i][j]*B.a[j][k])%MOD;
		return R;
	}
}I,tr[MAXN*4];
void build(LL i,LL l,LL r)
{
	if(l==r)
	{
		tr[i].a[1][1]=tr[i].a[1][2]=tr[i].a[2][1]=tr[i].a[2][2]=1;
		return ;
	}
	LL mid=(l+r)/2;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
	tr[i]=tr[i<<1]*tr[i<<1|1];
}
void updata(LL i,LL l,LL r,LL id)
{
	if(l==r)
	{
		tr[i].a[x][y]^=1;
		return ;
	}
	LL mid=(l+r)/2;
	if(mid>=id)
		updata(i<<1,l,mid,id);
	else
		updata(i<<1|1,mid+1,r,id);
	tr[i]=tr[i<<1]*tr[i<<1|1];
}
Matrix query(LL i,LL l,LL r)
{
	if(x>r || l>y || l>r) return I;
	if(x<=l && r<=y) return tr[i];
	LL mid=(l+r)/2;
	Matrix res=query(i<<1,l,mid);
	return res*query(i<<1|1,mid+1,r);
}
signed main()
{
	//freopen("fuck.in","r",stdin);
	//freopen("mine.out","w",stdout);
	I.a[1][1]=I.a[2][2]=1;
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		n--;
		build(1,1,n);
		while(m--)
		{
			LL op=read();
			if(op==1)
			{
				LL p=read();x=read();y=read();
				updata(1,1,n,p);
			}
			else
			{
				x=read();y=read();
				if(x>y) swap(x,y);
				y--;
				Matrix t=query(1,1,n);
				printf("%lld\n",(t.a[1][1]+t.a[1][2]+t.a[2][1]+t.a[2][2])%MOD);
			}
		}
	}
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!