Codeforces 题面传送门 & 洛谷题面传送门

一道 hot tea……听讲解时半懂不懂因为不知道题目意思,最后终究还是琢磨出来了(

首先注意到对于每个 \(a_i\),它具体是什么并不重要,我们只关心它的奇偶性,因为每次到达一个点后,如果后手有必胜策略,那么如果先手原地踏步,那么后手完全可以重复先手的操作直到 \(a_i\lt 2\) 为止,如果先手有必胜策略则反过来。由于每次走到一个点时候都要令 \(a_i\) 减 \(1\),因此我们可以直接令 \(a_i\leftarrow (a_i-1)\bmod 2\),这样游戏可以转化为,有 \(n\) 个 \([0,1]\) 中的整数 \(a_1,a_2,\cdots,a_n\),初始有一个棋子在 \(a_1\) 处,两个人轮流操作,每次一个人可以将棋子移到 \([i+1,\min(i+m,n)]\) 中的某个位置上,或者如果 \(a_i=1\),那么可以将棋子停留在原地并令 \(a_i=0\),不可以操作者输,问最终谁 win。

考虑暴力 \(dp\),\(dp_{i,j}\) 为当前棋子在 \(i\),\(a_i=j\) 的输赢状态,\(0\) 表示先手必输,\(1\) 表示先手必胜,那么显然 \(dp_{i,j}=1\) 当且仅当 \(\exists k\in[i+1,\min(i+m,n)]\) 满足 \(dp_{k,a_k}=0\),或者 \(j=1\) 且 \(dp_{i,0}=0\),否则 \(dp_{i,j}=0\)。

这样暴力做是 \(\mathcal O(nq)\) 的,考虑优化这个暴力,以下简记 \(dp_i=dp_{i,a_i}\),手玩一下样例就会发现一个 observation,那就是如果 \(a_i=1\),那么必有 \(dp_i=1\),因为如果 \([i+1,i+m]\) 中存在必输点那么移到那个必输点即可,否则 \(dp_{i,0}=0\),原地踏步即可。也就是说我们只用对于 \(a_i=0\) 检验 \([i+1,i+m]\) 中是否存在必输点即可。那么怎么检验呢?注意到这题的 \(m\) 令人出乎意料地小,\(2^m\) 不过 \(32\),并且涉及区间操作,因此可以想到线段树维护个什么东西。我们考虑对序列 \(a\) 建一棵线段树,线段树上每个区间 \([l,r]\) 开一个 \(2^m\) 的数组 \(to\),其中 \(to_S\) 表示如果 \(r+1,r+2,\cdots,r+m\) 是否为必胜点的状态为 \(S\)(\(0\):必输点;\(1\):必胜点),那么 \(l,l+1,\cdots,l+m-1\) 是否为必输点的状态是多少。这样显然可以在 \(\mathcal O(2^m)\) 的时间内合并 \([l,mid],[mid+1,r]\) 两个节点上的信息,初始状态:若 \(a_i=1\),那么 \(to_S=(2S+1)\&(2^m-1)\),其中 \(\&\) 为按位与,否则如果 \(S=2^m-1\) 那么 \(to_S=2^m-2\),否则 \(to_S\) 也等于 \((2S+1)\&(2^m-1)\)。最终求答案就将查询区间拆分一下、合并一下,如果查询得到的 \(to_0\) 的第一位为 \(0\),那么答案是 \(2\),否则答案是 \(1\)。至于那个区间加……显然如果 \(x\) 是偶数那么我们肯定不用关它,否则相当于翻转一个区间的 \(a\)(\(0\to 1,1\to 0\)),我们就记 \(b_i=2-a_i\),额外维护一下 \(b\) 数组的胜负情况,记作 \(to'\),翻转一整个区间时就直接交换它的 \(to\) 和 \(to'\) 即可,时间复杂度 \(2^mn\log n\),已经可以通过此题。

当然还有比正解更优秀的做法,其实只要加一个非常 simple 的 optimization 即可,注意到上面的做法中记录了一个二进制状态,费时费力,而其实我们只关心它第一个 \(0\) 的位置,因此我们可以将 \(to_i\) 的定义修改为:如果在 \(r\) 右边离 \(r\) 最近的必输点位置为 \(r+i\),那么在 \(l-1\) 右边离 \(l-1\) 最近的必输点位置为 \(l-1+to_i\),如果该位置 \(>l-1+m\) 那么 \(to_i=m+1\),显然在这种定义下我们可以 \(\mathcal O(m)\) 地合并序列信息,因此复杂度就降到了 \(mn\log n\)。

const int MAXN=2e5;
const int MAXM=5;
int n,m,qu;ll a[MAXN+5];
struct data{
int a[MAXM+3];
data(){memset(a,0,sizeof(a));}
friend data operator +(data x,data y){
data res;
for(int i=1;i<=m+1;i++) res.a[i]=y.a[x.a[i]];
return res;
}
};
struct node{int l,r,rev;data v[2];} s[MAXN*4+5];
void pushup(int k){
s[k].v[0]=s[k<<1|1].v[0]+s[k<<1].v[0];
s[k].v[1]=s[k<<1|1].v[1]+s[k<<1].v[1];
}
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;
if(l==r){
for(int i=1;i<=m;i++){
s[k].v[a[l]].a[i]=s[k].v[a[l]^1].a[i]=i+1;
} s[k].v[a[l]].a[m+1]=1;s[k].v[a[l]^1].a[m+1]=m+1;return;
} int mid=l+r>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
pushup(k);
}
void pushdown(int k){
if(s[k].rev){
swap(s[k<<1].v[0],s[k<<1].v[1]);s[k<<1].rev^=1;
swap(s[k<<1|1].v[0],s[k<<1|1].v[1]);s[k<<1|1].rev^=1;
s[k].rev=0;
}
}
void flip(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r) return swap(s[k].v[0],s[k].v[1]),s[k].rev^=1,void();
int mid=(pushdown(k),s[k].l+s[k].r>>1);
if(r<=mid) flip(k<<1,l,r);else if(l>mid) flip(k<<1|1,l,r);
else flip(k<<1,l,mid),flip(k<<1|1,mid+1,r);pushup(k);
}
data query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r) return s[k].v[0];
int mid=(pushdown(k),s[k].l+s[k].r>>1);
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return query(k<<1|1,mid+1,r)+query(k<<1,l,mid);
}
int main(){
scanf("%d%d%d",&n,&m,&qu);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]=(~a[i])&1;
build(1,1,n);
while(qu--){
int opt;scanf("%d",&opt);
if(opt==1){
int l,r;ll x;scanf("%d%d%lld",&l,&r,&x);
if(x&1) flip(1,l,r);
} else {
int l,r;scanf("%d%d",&l,&r);data t=query(1,l,r);
printf("%d\n",1+(t.a[m+1]==1));
}
}
return 0;
}

Codeforces 1076G - Array Game(博弈论+线段树)的更多相关文章

  1. Codeforces 1108E (Array and Segments) 线段树

    题意:给你一个长度为n的序列和m组区间操作,每组区间操作可以把区间[l, r]中的数字都-1,请选择一些操作(可以都不选),使得序列的最大值和最小值的差值尽量的大. 思路:容易发现如果最大值和最小值都 ...

  2. codeforces Good bye 2016 E 线段树维护dp区间合并

    codeforces Good bye 2016 E 线段树维护dp区间合并 题目大意:给你一个字符串,范围为‘0’~'9',定义一个ugly的串,即串中的子串不能有2016,但是一定要有2017,问 ...

  3. Codeforces 671C. Ultimate Weirdness of an Array(数论+线段树)

    看见$a_i\leq 200000$和gcd,就大概知道是要枚举gcd也就是答案了... 因为答案是max,可以发现我们很容易算出<=i的答案,但是很难求出单个i的答案,所以我们可以运用差分的思 ...

  4. codeforces 22E XOR on Segment 线段树

    题目链接: http://codeforces.com/problemset/problem/242/E E. XOR on Segment time limit per test 4 seconds ...

  5. Codeforces 588E. A Simple Task (线段树+计数排序思想)

    题目链接:http://codeforces.com/contest/558/problem/E 题意:有一串字符串,有两个操作:1操作是将l到r的字符串升序排序,0操作是降序排序. 题解:建立26棵 ...

  6. Codeforces Gym 100803G Flipping Parentheses 线段树+二分

    Flipping Parentheses 题目连接: http://codeforces.com/gym/100803/attachments Description A string consist ...

  7. Codeforces GYM 100114 D. Selection 线段树维护DP

    D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Descriptio ...

  8. Codeforces 444C DZY Loves Colors(线段树)

    题目大意:Codeforces 444C DZY Loves Colors 题目大意:两种操作,1是改动区间上l到r上面德值为x,2是询问l到r区间总的改动值. 解题思路:线段树模板题. #inclu ...

  9. Codeforces 85D Sum of Medians(线段树)

    题目链接:Codeforces 85D - Sum of Medians 题目大意:N个操作,add x:向集合中加入x:del x:删除集合中的x:sum:将集合排序后,将集合中全部下标i % 5 ...

随机推荐

  1. Salesforce 生命周期管理(二)Agile & Scrum 浅谈

    本篇参考: https://trailhead.salesforce.com/content/learn/modules/salesforce-agile-basics https://www.scr ...

  2. 测试小姐姐问我 gRPC 怎么用,我直接把这篇文章甩给了她

    原文链接: 测试小姐姐问我 gRPC 怎么用,我直接把这篇文章甩给了她 上篇文章 gRPC,爆赞 直接爆了,内容主要包括:简单的 gRPC 服务,流处理模式,验证器,Token 认证和证书认证. 在多 ...

  3. [敏捷软工团队博客]Beta阶段事后分析

    设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件要解决的问题是:现在的软工课程的作业分布在博客园.GitHub上,没有一个集成多种功能的一体化 ...

  4. [对对子队]会议记录4.19(Scrum Meeting10)

    今天已完成的工作 何瑞 ​ 工作内容:搭建第2关,基本完成第3关 ​ 相关issue:搭建关卡2.3 ​ 相关签入:4.19签入1 4.19签入2 刘子航 ​ 工作内容:完成关卡选择界面的设计图 ​ ...

  5. [火星补锅] siano 神奇的线段树

    前言: 本来以为很难打的,没想到主干一次就打对了,然而把输入的b和d弄混了,这sb错误调了两个小时... 解析: 神奇的线段树.注意到有一个性质,无论怎么割草,生长速度快的一定不会比生长速度慢的矮.因 ...

  6. 线程池系列二:一张动图,彻底懂了execute和submit

    ​ 我们知道线程池通过execute方法执行提交的Runnable任务,但Runnable只是执行任务,没有返回任何信息. [线程池原理:线程池原来是个外包公司,打工人我悟了] 若是我们想在异步执行完 ...

  7. HDMI之TMDS通道

    HDMI标准继续沿用了和DVI相同的,由Silicon Image公司发明的TMDS(Time Minimized Differential Signal)最小化传输差分信号传输技术.TMDS是一种微 ...

  8. PyPi到底是什么?pypi有啥作用?PyPi和pip有何渊源?

    转载:https://blog.csdn.net/weixin_42139375/article/details/82711201 可能有很多刚入行不久的朋友们,每天都在用pip 命令install ...

  9. Unmount and run xfs_repair

    参考连接:https://blog.csdn.net/qq_35022803/article/details/109287086 如故障图所示,sda3出现问题, 下面的解决办法: 解决办法: 原因: ...

  10. LOTO示波器配合VI曲线测试仪在电路板维修中的应用

    LOTO示波器配合VI曲线测试仪在电路板维修中的应用 市面上的VI曲线测试仪价格都在2000元到万元不等,同时大多携带不方便,有个别产品可以携带,但是功能单一(比如无法保存曲线,对比曲线等),那么LO ...