QOJ 6504. CCPC Final 2022 D Flower's Land 2题解

题意简述

给你一个只含 \(0,1,2\) 的序列,相邻两个相同的数字可以直接消掉。

询问包含两种

  • 区间所有数 \(+1\) 并对 \(3\) 取模。

  • 求一段区间能否用上述消除方式消完。

    样例输入

    8 9
    01211012
    2 4 5
    2 3 6
    1 6 8
    1 6 8
    2 3 6
    2 1 8
    1 1 1
    1 7 7
    2 1 8

    样例输出 #1

    Yes
    No
    Yes
    No
    Yes

提示

在我们做相邻两个能被消掉,判断一段区间能否被消掉时,常常用矩阵来考虑。

把每一种颜色用一种矩阵来表示,若当前位是偶数就设为这个矩阵,若当前位是奇数就设为这个矩阵的逆。

求解就把所有的矩阵乘起来,看最后结果矩阵是不是 \(I\) 。

为什么矩阵是正确的呢?因为矩阵满足结合律但不满足交换律。

这样就可以保证 \(1,2,3,1,2,3\) 会判断为错。

如果还没理解,下面再解释详细一点:

这是一段序列 \(0122221000\) 显然他是合法的。

在矩阵中,因为满足结合律,你先算中间那段 \(2222\) ,因为奇数和偶数个数相同,一定为 \(I\) ,相当于没有了,变成了 \(0110000\) 。一直向下就可以得到 \(I\)。

题解

我们用线段树来维护矩阵乘法,这很容易,具体就是加了以后如何在矩阵中体现出来。

因为只有 \(0,1,2\) ,我们把当前,\(+1\) 后, \(+2\) 后的矩阵都记录下来。这样就可以了。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e5 + 10, mod = 998244353;
int n,q;
char x;
int a[N], opt, l, r;
inline ll mpow(ll x,int k){
ll ans = 1;
while(k){
if(k & 1) ans = ans * x % mod;
x = x * x % mod;
k >>= 1;
}
return ans;
}
struct Mar{
ll a[3][3];
inline Mar operator *(const Mar b)const{
Mar c;
for(int i = 1; i <= 2; ++i){
for(int j = 1; j <= 2; ++j){
c.a[i][j] = 0;
for(int k = 1;k <= 2; ++k){
c.a[i][j] = (c.a[i][j] + a[i][k] * b.a[k][j] % mod) % mod;
}
}
}
return c;
}
inline bool check(){
if(a[1][1] != 1) return 0;
if(a[1][2] != 0) return 0;
if(a[2][1] != 0) return 0;
if(a[2][2] != 1) return 0;
return 1;
}
inline Mar inv()const{
Mar c, b;
c.a[1][1] = 1;
c.a[1][2] = 0;
c.a[2][1] = 0;
c.a[2][2] = 1;
for(int i = 1; i <= 2; ++i)for(int j = 1; j <= 2; ++j) b.a[i][j] = a[i][j];
for(int i = 1; i <= 2; ++i){
for(int j = 1; j <= 2; ++j){
if(i == j) continue;
ll w = b.a[j][i] * mpow(b.a[i][i],mod - 2) % mod;
for(int k = 1; k <= 2; ++k){
b.a[j][k] = (b.a[j][k] - b.a[i][k] * w % mod + mod) % mod;
}
for(int k = 1; k <= 2; ++k){
c.a[j][k] = (c.a[j][k] - c.a[i][k] * w % mod + mod) % mod;
}
}
}
for(int i = 1; i <= 2; ++i){
for(int j = 1; j <= 2; ++j){
c.a[i][j] = c.a[i][j] * mpow(b.a[i][i],mod - 2) % mod;
}
}
return c;
}
inline void print(){
for(int i = 1; i <= 2; ++i){
for(int j = 1; j <= 2; ++j){
cout<<a[i][j]<<' ';
}
cout<<'\n';
}
}
}I;
struct node{
Mar now,nxt,nnt;
int tag;
}tr[N << 2];
Mar m[3], m_[3];
inline void pre(){
I.a[1][1] = 1,
I.a[1][2] = 0;
I.a[2][1] = 0;
I.a[2][2] = 1; m[0].a[1][1] = 2,m[0].a[1][2] = 3;
m[0].a[2][1] = 5,m[0].a[2][2] = 7; m[1].a[1][1] = 11,m[1].a[1][2] = 13;
m[1].a[2][1] = 17,m[1].a[2][2] = 19; m[2].a[1][1] = 23,m[2].a[1][2] = 29;
m[2].a[2][1] = 31,m[2].a[2][2] = 37; m_[0] = m[0].inv();
m_[1] = m[1].inv();
m_[2] = m[2].inv();
}
inline void input(){
cin>> n >> q;
for(int i = 1; i <= n; ++i){
cin>>x;
a[i] = x - '0';
}
}
inline void pd(int x){
cout<<"now:"<<'\n';
tr[x].now.print();
cout<<"nxt:"<<'\n';
tr[x].nxt.print();
cout<<"nnt:"<<'\n';
tr[x].nnt.print();
cout<<"tag:"<<'\n'<<tr[x].tag<<'\n';
}
inline void downdate(int x){
tr[x << 1].tag = (tr[x << 1].tag + tr[x].tag) % 3;
tr[x << 1 | 1].tag = (tr[x << 1 | 1].tag + tr[x].tag) % 3;
while(tr[x].tag > 0){
swap(tr[x << 1].now, tr[x << 1].nxt);
swap(tr[x << 1].nnt, tr[x << 1].nxt);
swap(tr[x << 1 | 1].now, tr[x << 1 | 1].nxt);
swap(tr[x << 1 | 1].nnt, tr[x << 1 | 1].nxt);
--tr[x].tag;
}
}
inline void pushup(int x){
tr[x].now = tr[x << 1].now * tr[x << 1 | 1].now;
tr[x].nxt = tr[x << 1].nxt * tr[x << 1 | 1].nxt;
tr[x].nnt = tr[x << 1].nnt * tr[x << 1 | 1].nnt;
}
inline void build(int x, int l, int r){
if(l == r){
if(l % 2){
tr[x].now = m_[a[l]];
tr[x].nxt = m_[(a[l] + 1) % 3];
tr[x].nnt = m_[(a[l] + 2) % 3];
}else{
tr[x].now = m[a[l]];
tr[x].nxt = m[(a[l] + 1) % 3];
tr[x].nnt = m[(a[l] + 2) % 3];
}
return ;
}
int mid = (l + r) >> 1;
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1, r);
pushup(x);
}
inline void adtr(int x){
tr[x].tag = (tr[x].tag + 1) % 3;
swap(tr[x].now, tr[x].nxt);
swap(tr[x].nnt, tr[x].nxt);
}
inline void add(int x, int l, int r, int L, int R){
if(L <= l && r <= R){
adtr(x);
return ;
}
downdate(x);
int mid = (l + r) >> 1;
if(L <= mid) add(x << 1, l, mid, L, R);
if(R > mid) add(x << 1 | 1, mid + 1, r, L, R);
pushup(x);
}
inline Mar query(int x, int l, int r, int L, int R){
if(L <= l && r <= R){
// cout<<x<<'\n';
// tr[x].now.print();
return tr[x].now;
}
downdate(x);
int mid = (l + r) >> 1;
Mar ans = I;
if(L <= mid) ans = ans * query(x << 1, l, mid, L, R);
if(R > mid) ans = ans * query(x << 1 | 1,mid + 1, r, L, R);
return ans;
}
inline void op(){
build(1,1,n);
for(int i = 1; i <= q; ++i){
cin>> opt >> l >> r;
if(opt == 1){
add(1, 1, n, l, r);
}else if(opt == 2){
if(query(1, 1, n, l, r).check()){
cout<<"Yes"<<'\n';
}else{
cout<<"No"<<'\n';
}
}
}
} int main(){
cin.tie(0)->sync_with_stdio(false);
pre();
input();
op();
return 0;
}

QOJ 6504. CCPC Final 2022 D Flower's Land 2题解的更多相关文章

  1. 2018 ccpc final I. Cockroaches

    I. Cockroaches time limit per test6. s memory limit per test256 MB inputstandard input outputstandar ...

  2. CCPC final Cockroaches

    算法假了,我想的是通过枚举x,删除y的影响,这样答案第一个是没有任何问题的,但是第二个会算重复. 因为我枚举每一个x的时候,得到的y,而算另外一个x的时候,可能已经通过其他的点选到了这个点y这就有点麻 ...

  3. 2016-2017 National Taiwan University World Final Team Selection Contest (Codeforces Gym) 部分题解

      D 考虑每个点被删除时其他点对它的贡献,然后发现要求出距离为1~k的点对有多少个. 树分治+FFT.分治时把所有点放一起做一遍FFT,然后减去把每棵子树单独做FFT求出来的值. 复杂度$nlog^ ...

  4. 2018 CCPC 桂林游记

    TYPE: Onsite Contest NAME: 2018 - CCPC - Guilin PLAT: HUSTOJ TIME: 2018/10/28 09:00-14:00 CST LOCA: ...

  5. HDU-SupportOrNot训练实录

    菜鸡队训练实录. 现场赛记录: 2016:[名称:奖项/排名] ZJPSC:Gold/1 CCPC中南邀请赛:Gold/1 ICPC Dalian:Gold/24 ICPC Beijing:Gold/ ...

  6. HDU-AcmKeHaoWanLe训练实录

    菜鸡队训练实录. 现场赛记录:[名称:奖项/排名] 2017: ICPC Shenyang:Gold/3 CCPC Hangzhou:Gold/3 ICPC Beijing:Gold/13 CCPC ...

  7. Front Page

    General Team FST stay night from ShanDong University 19 - 20 CCPC QinHuangDao Gold (4 th) IUPC YinCh ...

  8. 牛客暑假多校第五场A.gpa

    一.题意 给出你的N门课程的考试成绩和所占的机电数目.允许你放弃K门课的成绩,要求你的平均学分绩最高能达到多少. Kanade selected n courses in the university ...

  9. ccpc 2018 final G - Pastoral Life in Stardew Valley

    #include <iostream> #include<cstdio> #include<cstring> #include<queue> using ...

  10. 2017 China Collegiate Programming Contest Final (CCPC 2017)

    题解右转队伍wiki https://acm.ecnu.edu.cn/wiki/index.php?title=2017_China_Collegiate_Programming_Contest_Fi ...

随机推荐

  1. golang 必会之 pprof 监控系列(5) —— cpu 占用率 统计原理

    golang pprof 监控系列(5) -- cpu 占用率 统计原理 大家好,我是蓝胖子. 经过前面的几节对pprof的介绍,对pprof统计的原理算是掌握了七八十了,我们对memory,bloc ...

  2. [Pytorch框架] 4.1 Fine tuning 模型微调

    文章目录 4.1 Fine tuning 模型微调 4.1.1 什么是微调 为什么要微调 迁移学习 Transfer Learning 二者关系 4.1.2 如何微调 4.1.3 注意事项 4.1.3 ...

  3. MySQL之主从复制搭建

    文章目录 主从复制 主从搭建 配置主从复制的命令 测试 总结 主从复制 主从也叫做(AB复制),允许一个服务器从一个服务器数据库(主服务器)的数据复制到一个或者多个MySQL数据库服务器. 主从复制的 ...

  4. LeetCode 双周赛 103(2023/04/29)区间求和的树状数组经典应用

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 大家好,我是小彭. 这场周赛是 LeetCode 双周赛第 103 场,难得在五一假期第一天打周赛的人数也没 ...

  5. 民谣女神唱流行,基于AI人工智能so-vits库训练自己的音色模型(叶蓓/Python3.10)

    流行天后孙燕姿的音色固然是极好的,但是目前全网都是她的声音复刻,听多了难免会有些审美疲劳,在网络上检索了一圈,还没有发现民谣歌手的音色模型,人就是这样,得不到的永远在骚动,本次我们自己构建训练集,来打 ...

  6. 2022-10-10:以下go语言代码输出什么?A:[1 2 3 0 1 2];B:死循环;C:[1 2 3 1 2 3];D:[1 2 3]。 package main import “fmt“

    2022-10-10:以下go语言代码输出什么?A:[1 2 3 0 1 2]:B:死循环:C:[1 2 3 1 2 3]:D:[1 2 3]. package main import "f ...

  7. 2022-10-04:以下go语言代码输出什么?A:{123} main.T{x:123} B:{123} T{x:123} C:boo boo D:boo main.T{x:123}。 packag

    2022-10-04:以下go语言代码输出什么?A:{123} main.T{x:123} B:{123} T{x:123} C:boo boo D:boo main.T{x:123}. packag ...

  8. 2020-12-10:i++是原子操作吗?为什么?

    福哥答案2020-12-10: 不是原子操作.i++分为三个阶段:1.内存到寄存器.2.寄存器自增.3.写回内存.这三个阶段中间都可以被中断分离开.***[评论](https://user.qzone ...

  9. 2021-12-19:找到所有数组中消失的数字。 给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums

    2021-12-19:找到所有数组中消失的数字. 给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内.请你找出所有在 [1, n] 范围内但没有出现在 nums ...

  10. vscode运行java输出至指定文件夹

    一.前言 最近呢,需要用vscode编写一点小的java程序,也就是单java文件,但是呢,我发现coderunner运行java,一个java文件编译出一个class文件,这也太乱了!不符合我简约的 ...