K. Addition Robot 2019-2020 ICPC, Asia Jakarta Regional Contest 線段樹

LINK

K. Addition Robot
time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
Adding two numbers several times is a time-consuming task, so you want to build a robot. The robot should have a string S=S1S2…SN of N characters on its memory that represents addition instructions. Each character of the string, Si, is either ‘A’ or ‘B’.

You want to be able to give Q commands to the robot, each command is either of the following types:

1 L R. The robot should toggle all the characters of Si where L≤i≤R. Toggling a character means changing it to ‘A’ if it was previously ‘B’, or changing it to ‘B’ if it was previously ‘A’.
2 L R A B. The robot should call f(L,R,A,B) and return two integers as defined in the following pseudocode:
function f(L, R, A, B):
FOR i from L to R
if S[i] = ‘A’
A = A + B
else
B = A + B
return (A, B)

You want to implement the robot’s expected behavior.

Input
Input begins with a line containing two integers: N Q (1≤N,Q≤100000) representing the number of characters in the robot’s memory and the number of commands, respectively. The next line contains a string S containing N characters (each either ‘A’ or ‘B’) representing the initial string in the robot’s memory. The next Q lines each contains a command of the following types.

1 L R (1≤L≤R≤N)
2 L R A B (1≤L≤R≤N; 0≤A,B≤109)
There is at least one command of the second type.
Output
For each command of the second type in the same order as input, output in a line two integers (separated by a single space), the value of A and B returned by f(L,R,A,B), respectively. As this output can be large, you need to modulo the output by 1000000007.
Example
inputCopy
5 3
ABAAA
2 1 5 1 1
1 3 5
2 2 5 0 1000000000
outputCopy
11 3
0 1000000000

在這裏插入圖片描述CF 的時候完全沒思路QAQ
第一份code是看了大佬的代碼(%%%)照着思路打的
照着模擬一遍 get 到了一些點 下下面還有自己的一點idea(敘述過於冗長)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,mod=1e9+7;
typedef long long ll;
int n,m;char s[N];
struct node{
	ll m[2][2];
	node(){
		for(int i=0;i<2;i++) for(int j=0;j<2;j++) m[i][j]=0;
	}
	friend node operator*(const node &a,const node &b)
	{//矩陣相乘 
		node c;
		for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
		{
		c.m[i][j]+=a.m[i][k]*b.m[k][j]; c.m[i][j]%=mod;	
		}
		return c;
	}
	void change(){//矩陣轉置 
		swap(m[1][1],m[0][0]);swap(m[1][0],m[0][1]);
	}
}t[N<<2],A,B;
int tag[N<<2];//懶標記 
void build(int l,int r,int rt)
{
	if(l==r)
	{
		if(s[l]=='A') t[rt]=A;
		else t[rt]=B; 
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,rt<<1|1);
	t[rt]=t[rt<<1]*t[rt<<1|1];
}
void pushdown(int rt)
{
	tag[rt]=0;
	tag[rt<<1|1]^=1;
	tag[rt<<1]^=1;
	t[rt<<1].change();
	t[rt<<1|1].change(); 
}
void update(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R) 
	{
		tag[rt]^=1;
		t[rt].change();
		return ;
	}
	if(tag[rt]) pushdown(rt);
	int mid=(l+r)>>1;
	if(L<=mid) update(L,R,l,mid,rt<<1);
	if(R>mid) update(L,R,mid+1,r,rt<<1|1);
	t[rt]=t[rt<<1]*t[rt<<1|1];
}
node query(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R) 
	{
		return t[rt];
	}
	if(tag[rt]) pushdown(rt);
	int mid=(l+r)>>1;
	node ans;
	ans.m[0][0]=ans.m[1][1]=1;
	if(L<=mid) ans=(ans*query(L,R,l,mid,rt<<1));
	if(R>mid)  ans=(ans*query(L,R,mid+1,r,rt<<1|1));
	return ans;
}
int main()
{
	A.m[0][1]=A.m[0][0]=A.m[1][1]=1;//A=A+B
	B.m[1][1]=B.m[1][0]=B.m[0][0]=1; //B=A+B 
	cin>>n>>m>>(s+1);
	reverse(s+1,s+1+n);
	build(1,n,1);int l, r;ll a,b;
	while(m--)
	{
		int op;scanf("%d",&op);
		if(op==1)
		{
			scanf("%d%d",&l,&r);
			update(n+1-r,n+1-l,1,n,1);//更新 
		}else 
		{
			scanf("%d%d%lld%lld",&l,&r,&a,&b);
			node ans=query(n+1-r,n+1-l,1,n,1);//詢問 
			printf("%lld %lld\n",(ans.m[0][1]*b%mod+ans.m[0][0]*a%mod)%mod,(ans.m[1][0]*a%mod+ans.m[1][1]*b%mod)%mod);
		}
	}
}

->->仔細想想自己改了一下就是正常的矩陣相乘A * B=C 就應該是C中(X,Y)位置上的數值就應該是A中 X這一行的數乘以對應的B 中Y列上面的數之和 稍微改變一下,考慮矩陣C(X,Y)上的數是由 A X列的數乘以B Y行的數之和

二維矩陣(矩陣用來存係數啊
X Y----A
Z K----B
(X ,Z分別表示 此時 A B中a的係數,同理Y ,K 分別表示A B中b的係數
AA BB也就是代碼裏的A,B這裏爲了不弄混
AA矩陣://對應A =A+B
1 1
0 1

BB矩陣://B=A+B
1 0
1 1
考慮~對應的元素是A就把目前B累計的a,b,係數全部累加到A上,B不變
對應的是B就把A的a,b係數全部累加到B上 A不變
按以上的想法):對於A B序列從A到B 採用ans=pre(之前的矩陣也就是AA )*目前的元素矩陣(BB) =
AA *BB =
1 1
1 2

對於所得的矩陣也就是即爲C C(0,0)=AA(0,0)*BB(0,0)+AA(1,0)*BB(0,1)
=1 * 1+0 * 1=1 也就是ans中A對應的a的係數 …
這時候就是上面矩陣AA BB 的作用 BB的第一行1 0 與前面pre中的a係數分別相乘,現在對於此時A的a係數只能接受來自上一個A本身的a而拒絕來自上一個B的a ,而第二行 1 1 表示此時的B的a(或b)可以接受來自之前A 的a(b)也可以接受來自之前B的a(b)
其餘同理啊

~~感覺越講越亂啊 明明超級簡單的QAQ


代碼

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,mod=1e9+7;
typedef long long ll;
int n,m;char s[N];
struct node{
	ll m[2][2];
	node(){
		for(int i=0;i<2;i++) for(int j=0;j<2;j++) m[i][j]=0;
	}
	//和上一份code主要區別就是下面的opertor裏面的a b交換位子,實現矩陣乘法的重置!!!
	friend node operator*(const node &b,const node &a)
	{//矩陣相乘 
		node c;
		for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++)
		{
		c.m[i][j]+=a.m[i][k]*b.m[k][j]; c.m[i][j]%=mod;	
		}
		return c;
	}
	void change(){//矩陣轉置 
		swap(m[1][1],m[0][0]);swap(m[1][0],m[0][1]);
	}
}t[N<<2],A,B;
int tag[N<<2];//懶標記 
void build(int l,int r,int rt)
{
	if(l==r)
	{
		if(s[l]=='A') t[rt]=A;
		else t[rt]=B; 
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,rt<<1|1);
	t[rt]=t[rt<<1]*t[rt<<1|1];
}
void pushdown(int rt)
{
	tag[rt]=0;
	tag[rt<<1|1]^=1;
	tag[rt<<1]^=1;
	t[rt<<1].change();
	t[rt<<1|1].change(); 
}
void update(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R) 
	{
		tag[rt]^=1;
		t[rt].change();
		return ;
	}
	if(tag[rt]) pushdown(rt);
	int mid=(l+r)>>1;
	if(L<=mid) update(L,R,l,mid,rt<<1);
	if(R>mid) update(L,R,mid+1,r,rt<<1|1);
	t[rt]=t[rt<<1]*t[rt<<1|1];
}
node query(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R) 
	{
		return t[rt];
	}
	if(tag[rt]) pushdown(rt);
	int mid=(l+r)>>1;
	node ans;
	ans.m[0][0]=ans.m[1][1]=1;
	if(L<=mid) ans=(ans*query(L,R,l,mid,rt<<1));
	if(R>mid)  ans=(ans*query(L,R,mid+1,r,rt<<1|1));
	return ans;
}
int main()
{
	A.m[0][1]=A.m[0][0]=A.m[1][1]=1;//A=A+B
	B.m[1][1]=B.m[1][0]=B.m[0][0]=1; //B=A+B 
	cin>>n>>m>>(s+1);
	//reverse(s+1,s+1+n);
	build(1,n,1);int l, r;ll a,b;
	while(m--)
	{
		int op;scanf("%d",&op);
		if(op==1)
		{
			scanf("%d%d",&l,&r);
			update(l,r,1,n,1);//更新 
		}else 
		{
			scanf("%d%d%lld%lld",&l,&r,&a,&b);
			node ans=query(l,r,1,n,1);//詢問 
			printf("%lld %lld\n",(ans.m[0][1]*b%mod+ans.m[0][0]*a%mod)%mod,(ans.m[1][0]*a%mod+ans.m[1][1]*b%mod)%mod);
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章