題目鏈接:點擊查看
題目大意:給出一個只由 A 和 B 組成的字符串 s ,需要完成 m 次操作,每次操作分為兩種類型:
1 l r :將 [ l , r ] 內的字符串 A 變成 B,B 變成 A2 l r a b:從左到右掃一遍字符串 s 的 [ l , r ] ,并求出最后的 a 和 b 如果 s[ i ] == ' B ' : b = a + b如果 s[ i ] == ' A ' : a = a + b
題目分析:維護一段連續的 a 和 b 的變化,通過觀察后不難發現其實可以用矩陣去維護:
這樣操作二就得以維護了,但操作一該如何維護呢,如果只是觀察單純的一個 A 和 B 的轉移矩陣,可以發現是經過上下翻轉然后再經過左右翻轉得到的,利用矩陣乘法多觀察一下,當 n 大于一時,執行操作一后,同樣也是需要將矩陣進行上下翻轉然后左右翻轉再得到的,證明的話我也不會,畢竟比賽的時候也不會考察證明嘛
所以對于操作一,寫一個 reverse 函數執行上述操作即可
區間查詢的話,可以用線段樹維護矩陣,這樣可以實現區間更新以及區間查詢
代碼:
?
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;const int mod=1e9+7;char s[N];struct Ma
{LL a[2][2];Ma operator*(const Ma& t){Ma ans;for(int i=0;i<2;i++)for(int j=0;j<2;j++){ans.a[i][j]=0;for(int k=0;k<2;k++)ans.a[i][j]=(ans.a[i][j]+a[i][k]*t.a[k][j])%mod;}return ans;}
}one;struct Node
{int l,r;int rev;Ma maze;
}tree[N<<2];void pushup(int k)
{tree[k].maze=tree[k<<1].maze*tree[k<<1|1].maze;
}void reverse(int k)
{swap(tree[k].maze.a[0][0],tree[k].maze.a[0][1]);swap(tree[k].maze.a[1][0],tree[k].maze.a[1][1]);swap(tree[k].maze.a[0][0],tree[k].maze.a[1][0]);swap(tree[k].maze.a[0][1],tree[k].maze.a[1][1]);
}void pushdown(int k)
{if(tree[k].rev){tree[k].rev=0;tree[k<<1].rev^=1;tree[k<<1|1].rev^=1;reverse(k<<1);reverse(k<<1|1);}
}void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;tree[k].rev=0;if(l==r){if(s[l]=='A'){tree[k].maze.a[0][0]=1;tree[k].maze.a[0][1]=0;tree[k].maze.a[1][0]=1;tree[k].maze.a[1][1]=1;}else{tree[k].maze.a[0][0]=1;tree[k].maze.a[0][1]=1;tree[k].maze.a[1][0]=0;tree[k].maze.a[1][1]=1;}return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}void update(int k,int l,int r)
{if(tree[k].r<l||tree[k].l>r)return;if(tree[k].l>=l&&tree[k].r<=r){reverse(k);tree[k].rev^=1;return;}pushdown(k);update(k<<1,l,r);update(k<<1|1,l,r);pushup(k);
}Ma query(int k,int l,int r)
{if(tree[k].r<l||tree[k].l>r)return one;if(tree[k].l>=l&&tree[k].r<=r)return tree[k].maze;pushdown(k);return query(k<<1,l,r)*query(k<<1|1,l,r);
}void init()
{one.a[0][0]=1;one.a[0][1]=0;one.a[1][0]=0;one.a[1][1]=1;
}int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);init();int n,m;scanf("%d%d",&n,&m);scanf("%s",s+1);build(1,1,n);while(m--){int op;scanf("%d",&op);if(op==1){int l,r;scanf("%d%d",&l,&r);update(1,l,r);}else{int l,r,a,b;scanf("%d%d%d%d",&l,&r,&a,&b);Ma ans2=query(1,l,r);Ma ans1;ans1.a[0][0]=a;ans1.a[0][1]=b;ans1.a[1][0]=0;ans1.a[1][1]=0;Ma ans=ans1*ans2;printf("%lld %lld\n",ans.a[0][0],ans.a[0][1]);}}return 0;
}
?
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生
總結
以上是生活随笔為你收集整理的CodeForces - 1252K Addition Robot(线段树维护矩阵)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。