CodeForces - 1252K Addition Robot(线段树维护矩阵)
题目链接:点击查看
题目大意:给出一个只由 A 和 B 组成的字符串 s ,需要完成 m 次操作,每次操作分为两种类型:
- 1 l r :将 [ l , r ] 内的字符串 A 变成 B,B 变成 A
- 2 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;
}
CodeForces - 1252K Addition Robot(线段树维护矩阵)相关推荐
- 【2019牛客暑期多校训练营(第二场)- E】MAZE(线段树优化dp,dp转矩阵乘法,线段树维护矩阵乘法)
题干: 链接:https://ac.nowcoder.com/acm/contest/882/E?&headNav=acm 来源:牛客网 Given a maze with N rows an ...
- HDU - 6967 G I love data structure 线段树维护矩阵 + 细节
传送门 文章目录 题意: 思路: 题意: 给你两个长度为nnn的数组a,ba,ba,b,你需要完成如下四种操作: 思路: 思路还是比较简单的,首先建一颗线段树,线段树中维护a,b,a2,b2,aba, ...
- 2019ICPC(南昌) - Hello 2019(动态规划+线段树维护矩阵)
题目链接:点击查看 题目大意:给出一个长度为n的只由数字组成的字符串,再给出m个询问,每次询问给出闭区间[l,r],求区间内想要包含"9102",但不包含"8102&qu ...
- CF719E. Sasha and Array [线段树维护矩阵]
CF719E. Sasha and Array 题意: 对长度为 n 的数列进行 m 次操作, 操作为: a[l..r] 每一项都加一个常数 C, 其中 0 ≤ C ≤ 10^9 求 F[a[l]]+ ...
- [动态dp]线段树维护转移矩阵
背景:czy上课讲了新知识,从未见到过,总结一下. 所谓动态dp,是在动态规划的基础上,需要维护一些修改操作的算法. 这类题目分为如下三个步骤:(都是对于常系数齐次递推问题) 1先不考虑修改,不考虑区 ...
- Codeforces Round #343 (Div. 2) D. Babaei and Birthday Cake 线段树维护dp
D. Babaei and Birthday Cake 题目连接: http://www.codeforces.com/contest/629/problem/D Description As you ...
- Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)
题意: 操作1:把x位置的数字修改成y. 操作2:查询[l,r]之间不下降序列的个数. 题解: 线段树维护区间和问题 (这是套路,想不到只能说做题少别打我) . 用五个变量进行维护. sum区间总个数 ...
- Codeforces Round #603 (Div. 2) E. Editor 线段树维护括号序列
传送门 文章目录 题意: 思路: 题意: 思路: 首先一个括号序列合法的条件可以转化成两个(左括号代价为111,右括号代价为−1-1−1): (1) 左括号个数等于右括号个数. (2) 括号的前缀和非 ...
- Codeforces 833B 题解(DP+线段树)
题面 传送门:http://codeforces.com/problemset/problem/833/B B. The Bakery time limit per test2.5 seconds m ...
最新文章
- C++ Primer英文版(第5版)
- libevent 实现的socket 通信 server以及解决找不到动态库的方法
- [转]Linux 进程间通信:共享内存
- apache shiro jar包_只需要6个步骤,springboot集成shiro,并完成登录
- spring mvc使用html页面,使用Spring MVC的纯HTML页面应用程序
- 微分方程的数值解法与程序实现 pdf_初中数学知识点|一元一次方程的概念及讲解(二)建议收藏!内含pdf版...
- 比特币 源代码_GitHub遭黑客攻击:窃取数百源码并勒索比特币,数量惊人!
- PHP冒泡排序(Bubble Sort)算法详解
- tkinter要安装吗 苹果_建造存10万斤的苹果保鲜冷库安装工程要考虑哪些因素?...
- kettle spoon判断增量更新_【论文推荐】张斌等:基于改进 SOINN 算法的恶意软件增量检测方法...
- PHP语言编程实现采集远程图片资源
- 需求不容易确定的项目不要接
- Zookeeper,Hbase 伪分布,集群搭建
- 带你啃透深度学习必学“圣经”花书!(附带论文代码精读讲解)
- 带头节点 (非头指针) 双向链表 (doubly linked list)
- 泛函分析笔记0:绪论
- 在企业工作一年多的几点感悟
- 统信UOS应用商店十月活动
- 绝地大逃杀官方指定迅游加速
- Axure元件之文本框的案例