Harry And Math Teacher

一、题目

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

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

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

二、解法

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

然后发现可以用线段树优化,第一个操作就是一个单点修改,第二个操作就是一个区间查询,时间复杂度 O ( n log n ) 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);
			}
		}
	}
}
发布了192 篇原创文章 · 获赞 12 · 访问量 3347

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/103826821
今日推荐