不想写昨天晚上cf的比赛题目所以来写题解摸摸鱼

题目大意

有一个在长度为\(k\)的正整数序列\(b\)上进行的游戏,一开始一个棋子放在位置\(1\),假如当前棋子的位置为\(x\),你可以做如下两种操作:

  1. 给\(b_x\)减少\(1\),要求操作后\(b_x\)还是正整数
  2. 把棋子移动到\([x+1,\min(x+m,k)]\)

无法操作的人就输了。现在两个人轮流做游戏,你要判断先手还是后手胜利。

给你一个长度为\(n\)的序列\(a\),你要支持如下两种操作:

  1. 区间加
  2. 查询给定区间内进行的游戏是否是先手必胜的,游戏不实际进行(这个查询不改变区间内的数的值)

做法

首先我们只考虑给定一个序列,上面进行的游戏如何判断先后手必胜状态。

这看着很像限制了取石子数量的单个堆上的Nim游戏。但是偶数位置有一些不同。

先来画一画SG图:(结点标号为\((x, b_x)\))

假如目前棋子放在一个值为偶数的位置,那么先手必胜:记后面可以转移到的位置的SG函数值的\(MEX\)为\(MEX\)(表述好怪),那么\(b_x=1\)时当前的SG函数值一定是\(MEX\),\(b_x=2\)是 \(MEX+1\),\(b_x=3\)又是\(MEX\),以此类推。所以值为偶数的位置一定是必胜的。

然后假如没有偶数值的位置的话,序列的状态应该看起来像这样:(W为必胜,L为必败,下同)

\[WWWLWW...WWWLWWWLWWWL
\]

那么在\(W\)位置的值假如是偶数,显然对每个结点没有任何影响,假如在\(L\)位置有一个偶数值呢?比如\(WWWLWWWL\)的第一个\(L\)位置,现在被改成了偶数值,也就是变成\(W\)了,那么结果为\(WWLWWWWL\),也就是相当于\(L\)位置被往前传递了。

因为每\(M\)(此处\(M\)为题目中的\(m+1\),表示循环节,下同)个位置会有一个\(L\)位置,那么在\(L\)位置之前的第一个和它的距离模\(M\)为\(0\)的偶数值位置会向前传递一次\(L\)位置。

接下来考虑如何维护区间的信息。

由于只有奇偶性影响答案,所以首先我们只需要维护\(01\)序列表示奇偶性就行。那么区间加一个奇数就相当于翻转\(01\)。现在要维护的区间信息有:区间长度\(len\)、区间翻转懒标记\(tag\)。

然后我们需要支持区间合并和查询答案,所以还要维护一点东西:假设\(X\)会向前传递\(L\)位置(\(X\in {0,1}\),为序列上某一位的值,对称维护是为了翻转操作考虑),假设最后一个\(X\)和序列末尾的距离为\(D\),那么会有多少个\(X\)向前传递\(L\)位置,记作\(cnt_{X,D}\)。

有了\(len\)和\(cnt_{X,D}\),我们可以计算出区间最前面的\(L\)位置和区间开头的距离(包含\(L\)位置自身,因为有\(L\)被传递到了整个区间的前面的情况)为\((len-D-cnt_{X,D})\mod M\)。先手必胜当且仅当:\(len-cnt_{0,0} \neq 1\)。

然后合并区间也比较方便,直接枚举右侧子区间的\(X\)和\(D\),那么新区间的\(cnt\)就为:

\[cnt_{X,D}=rcnt_{X,D}+lcnt_{X,(M-(rlen-D-rcnt_{X,D}))\mod M};
\]

区间长度直接相加,区间翻转就交换\(cnt_0\)和\(cnt_1\),接下来就线段树维护这些信息即可。

代码

#include<bits/stdc++.h>
using namespace std; int m; struct node{
int len,tag,cnt[2][6];
node(){
len=tag=0;
memset(cnt,0,sizeof(cnt));
}
node(int x){
len=1;
tag=0;
memset(cnt,0,sizeof(cnt));
cnt[x][0]=1;
}
void flip(){
tag^=1;
swap(cnt[0],cnt[1]);
}
void pushdown(node &l,node &r){
if(tag){
l.flip();
r.flip();
tag=0;
}
}
void merge(const node &l,const node &r){
len=l.len+r.len;
tag=0;
for(int v=0;v<2;v++)
for(int i=0;i<m;i++){
cnt[v][i]=r.cnt[v][i]+l.cnt[v][(m-(r.len-i-r.cnt[v][i])%m)%m];
}
}
bool win(){
return (len-cnt[0][0])%m!=1;
}
}; typedef long long ll; struct SegTree{
int sz;
vector<node> dat; void build(ll *a,int n,int id,int l,int r){
if(l==r){
if(l<=n){
dat[id]=node(a[l]&1);
}
return;
}
build(a,n,id<<1,l,l+r>>1);
build(a,n,id<<1|1,(l+r>>1)+1,r);
dat[id].merge(dat[id<<1],dat[id<<1|1]);
} SegTree(int _sz,ll *a){
sz=1;
while(sz<_sz)sz<<=1;
dat.resize(sz<<1);
build(a,_sz,1,1,sz);
} void upd(int id,int l,int r,int ql,int qr){
if(qr<l||r<ql)return;
if(ql<=l&&r<=qr){
dat[id].flip();
return;
}
dat[id].pushdown(dat[id<<1],dat[id<<1|1]);
upd(id<<1,l,l+r>>1,ql,qr);
upd(id<<1|1,(l+r>>1)+1,r,ql,qr);
dat[id].merge(dat[id<<1],dat[id<<1|1]);
} void upd(int l,int r){
upd(1,1,sz,l,r);
} node qry(int id,int l,int r,int ql,int qr){
if(qr<l||r<ql)return node();
if(ql<=l&&r<=qr){
return dat[id];
}
dat[id].pushdown(dat[id<<1],dat[id<<1|1]);
node res;
res.merge(qry(id<<1,l,l+r>>1,ql,qr),qry(id<<1|1,(l+r>>1)+1,r,ql,qr));
return res;
} bool qry(int l,int r){
return qry(1,1,sz,l,r).win();
}
}; int n,q;
ll a[200005]; int main(){ ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0); cin>>n>>m>>q;
m++;
for(int i=1;i<=n;i++)cin>>a[i];
SegTree st(n,a);
while(q--){
int t,l,r;
ll x;
cin>>t>>l>>r;
if(t==1){
cin>>x;
if(x&1)st.upd(l,r);
}else{
cout<<(st.qry(l,r)?"1\n":"2\n");
}
} return 0;
}

Codeforces 1076G Array Game 题解的更多相关文章

  1. Codeforces 1076G - Array Game(博弈论+线段树)

    Codeforces 题面传送门 & 洛谷题面传送门 一道 hot tea--听讲解时半懂不懂因为不知道题目意思,最后终究还是琢磨出来了( 首先注意到对于每个 \(a_i\),它具体是什么并不 ...

  2. Codeforces Round #543 Div1题解(并不全)

    Codeforces Round #543 Div1题解 Codeforces A. Diana and Liana 给定一个长度为\(m\)的序列,你可以从中删去不超过\(m-n*k\)个元素,剩下 ...

  3. Codeforces Round #545 Div1 题解

    Codeforces Round #545 Div1 题解 来写题解啦QwQ 本来想上红的,结果没做出D.... A. Skyscrapers CF1137A 题意 给定一个\(n*m\)的网格,每个 ...

  4. Codeforces Round #539 Div1 题解

    Codeforces Round #539 Div1 题解 听说这场很适合上分QwQ 然而太晚了QaQ A. Sasha and a Bit of Relax 翻译 有一个长度为\(n\)的数组,问有 ...

  5. [Codeforces Round #461 (Div2)] 题解

    [比赛链接] http://codeforces.com/contest/922 [题解] Problem A. Cloning Toys          [算法] 当y = 0 ,   不可以 当 ...

  6. Codeforces 7E - Defining Macros 题解

    目录 Codeforces 7E - Defining Macros 题解 前言 做法 程序 结尾 Codeforces 7E - Defining Macros 题解 前言 开始使用博客园了,很想写 ...

  7. Educational Codeforces Round 64 部分题解

    Educational Codeforces Round 64 部分题解 不更了不更了 CF1156D 0-1-Tree 有一棵树,边权都是0或1.定义点对\(x,y(x\neq y)\)合法当且仅当 ...

  8. Educational Codeforces Round 64部分题解

    Educational Codeforces Round 64部分题解 A 题目大意:给定三角形(高等于低的等腰),正方形,圆,在满足其高,边长,半径最大(保证在上一个图形的内部)的前提下. 判断交点 ...

  9. Codeforces 1108E2 Array and Segments (Hard version) 差分, 暴力

    Codeforces 1108E2 E2. Array and Segments (Hard version) Description: The only difference between eas ...

随机推荐

  1. 到底什么是自动化优先思维?与RPA有什么关系?

    基于RPA的自动化优先,正在成为广大组织的主流管理思维 到底什么是自动化优先思维?与RPA有什么关系? 如何用RPA简单快速的打造一个自动化优先的组织? 文/王吉伟 在IT运维项目中,组织经常会遇到先 ...

  2. 最新的Android Sdk 使用Ant多渠道批量打包

    实例工程.所需的文件都在最后的附件中.    今天花费了几个小时,参考网上的资料,期间遇到了好几个问题, 终于实现了使用Ant批量多渠道打包,现在,梳理一下思路,总结使用Ant批量多渠道打包的方法:1 ...

  3. java标识接口

    标识接口是没有任何方法和属性的接口,标识接口不对实现类有任何语义上的要求,仅仅表明它的实现类属于一个特定的类型.它非常类似于Web 2.0中的TAG的概念,Java使用它标识某一类对象.主要有两个用途 ...

  4. 【Java 8】Stream API

    转自 Java 8 Stream Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式.Stream 是Java8中处理集合的关键抽象概念,它可以对集合进 ...

  5. 小飞机可以解决git clone没有返回的问题吗?

    [1]Linux如何使用小飞机? 以ss为例,先下载客户端: https://www.mediafire.com/folder/xag0zy318a5tt/Linux 下载客户端以后,右键把权限中&q ...

  6. 阿里云发布CloudOps白皮书,ECS自动化运维套件新升级

    12月10 日,2021云上架构与运维峰会上,阿里云发布业界首部<云上自动化运维白皮书>(简称CloudOps白皮书),并在其中提出了CloudOps成熟度模型.同时,阿里云还宣布了ECS ...

  7. 2、Spring的IOC标签介绍以及实例

    一.Spring_ioc配置文件bean标签介绍 1. bean标签 名称:bean 类型:标签 归属:beans标签 作用:定义spring中的资源,受此标签定义的资源将受到spring控制 格式: ...

  8. Jenkins安全加固

    1.jenkins未授权访问 描述 jenkins不当配置可导致未授权访问管理控制台,可以通过脚本命令行执行系统命令.通过该漏洞,可以后台管理服务,通过脚本命令行功能执行系统命令,如反弹shell,w ...

  9. CF716A Crazy Computer 题解

    Content 有一个电脑,如果过了 \(c\) 秒之后还没有任何打字符的操作,就把屏幕上面所有的字符清空.现在,给定 \(n\) 次打字符的时间 \(t_1,t_2,...,t_n\),求最后屏幕剩 ...

  10. java 编程基础 注解 :可重复的注解

    重复注解 Java8以前,同一个程序元素前最多只能使用一相同类型的注解;如果需要在同一个元素前使用多个相同类型的注解,则必须使用注解"容器".例如在Struts开发中,有时需要在 ...