传送门

神仙题! 听@Yubai给我讲了半个下午,快%@Yubai

  • 见到这些奇奇怪怪的题是不是应该试着证下状态数上界啊

首先观察题目里给的柿子,可以发现 \(or-and\) 单调增, \(min-max\) 单调减

神仙思路,发现对于一个给定的端点,我怀疑出题人是左撇子,不同的 \(or-and\) 最多只有 \(2logn\) 个,证明应该很简单

那尝试把这些 \(or-and\) 相同的区间拎出来,从右向左枚举区间,在区间内二分可得合法的最远右端点

然后问题来了:如何 \(O(1)\) 维护出这些区间

神仙思路,考虑什么是这些区间的边界,会发现一个数是边界当且仅当这一位上出现了之前没有在这一位上出现过的数

也即比如左边界上第 \(i\) 位是1,那向右找到第一个这一位上是0的数,那个数就会是一个边界

这个可以维护出一个next0和一个next1单调指针,每次排个序处理

然后区间最值,区间与或都需要 \(O(1)\) 出,都可以用ST表

  • 所以满足区间可重性的东西都可以用ST表?

  • 关于区间整体取max:

    另一种实现方法是把线段差分,拆分为在 \(l\) 插入一个长度,在 \(r\) 删除一个长度的事件,拿一个multiset维护,每次取出最大值即可

    但这样要求区间数不能太多

  • 关于ST表和lca的fa数组:

    把大小是log的那一维放在前面真的会快

然后具体实现上注意我让每个端点是区间的右端点,所以每次还得特别把位置 \(n\) 扔进去

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define reg register int
#define fir first
#define sec second
#define make make_pair
#define max2(a, b) ((a)>(b)?(a):(b))
#define min2(a, b) ((a)<(b)?(a):(b))
//#define int long long char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans;
} int n, k;
int ta1[28][N], ta2[28][N], ta3[28][N], ta4[28][N], top, lg[N], a[N];
pair<int, int> add[N], del[N];
multiset<int> s;
struct point{
int dlt, pos0, pos1;
point():pos0(1),pos1(1){}
int nxt0(int i) {
//cout<<"nxt0: "<<i<<' '<<pos0<<endl;
if (i>=pos0) {pos0=i+1; i=1<<dlt; while (pos0<=n && (a[pos0]&i)) ++pos0;}
//cout<<"return "<<pos0<<endl;
return pos0;
}
int nxt1(int i) {
if (i>=pos1) {pos1=i+1; i=1<<dlt; while (pos1<=n && !(a[pos1]&i)) ++pos1;}
return pos1;
}
}p[28];
inline int qmin(int l, int r) {
int t=lg[r-l+1]-1;
return min(ta2[t][l], ta2[t][r-(1<<t)+1]);
}
inline int qmax(int l, int r) {
int t=lg[r-l+1]-1;
return max(ta1[t][l], ta1[t][r-(1<<t)+1]);
}
inline int qor(int l, int r) {
int t=lg[r-l+1]-1;
return ta3[t][l]|ta3[t][r-(1<<t)+1];
}
inline int qand(int l, int r) {
int t=lg[r-l+1]-1;
return ta4[t][l]&ta4[t][r-(1<<t)+1];
} signed main()
{
n=read(); k=read();
for (reg i=1; i<=n; ++i) a[i]=read();
for (reg i=1; i<=n; ++i) ta1[0][i]=ta2[0][i]=ta3[0][i]=ta4[0][i]=a[i];
for (reg i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
int lim=lg[n]-1;
for (reg j=0; j<lim; ++j)
for (reg i=1,t,lm=n-(1<<(j+1))+1; i<=lm; ++i) {
t=i+(1<<j);
ta1[j+1][i]=max2(ta1[j][i], ta1[j][t]);
ta2[j+1][i]=min2(ta2[j][i], ta2[j][t]);
ta3[j+1][i]=ta3[j][i]|ta3[j][t];
ta4[j+1][i]=ta4[j][i]&ta4[j][t];
}
for (reg i=0; i<27; ++i) p[i].dlt=i;
int tem[30];
for (reg i=1; i<=n; ++i) {
//cout<<"i="<<i<<": "<<endl;
for (reg j=0; j<27; ++j) tem[j]=(a[i]&(1<<j))?p[j].nxt0(i):p[j].nxt1(i);
tem[27]=i; tem[28]=n+1;
sort(tem, tem+29);
//assert(tem[0]==i);
//cout<<"tem: "; for (int i=0; i<=27; ++i) cout<<tem[i]<<' '; cout<<endl;
for (reg j=28,t1,t2,l,r,mid; j; --j) {
if (tem[j-1]==tem[j]) continue;
t1=qor(i, tem[j]-1)-qand(i, tem[j]-1), t2=qmin(i, tem[j-1])-qmax(i, tem[j-1]);
if (t1+t2>=k) {
//cout<<"t1="<<t1<<" and t2="<<t2<<' '<<t1+t2<<endl;
//cout<<"tem_j: "<<tem[j-1]<<' '<<tem[j]-1<<endl;
l=tem[j-1], r=tem[j]-1;
while (l<=r) {
mid=(l+r)>>1;
if (t1+qmin(i, mid)-qmax(i, mid)>=k) l=mid+1;
else r=mid-1;
}
//cout<<"lr: "<<l<<' '<<r<<endl;
add[++top]=make(i, l-i), del[top]=make(l, l-i);
break;
}
}
}
sort(del+1, del+top+1);
int pos1=1, pos2=1;
//cout<<"---add---"<<endl; for (int i=1; i<=top; ++i) cout<<add[i].fir<<','<<add[i].sec<<endl;
//cout<<"---del---"<<endl; for (int i=1; i<=top; ++i) cout<<del[i].fir<<','<<del[i].sec<<endl;
for (reg i=1; i<=n; ++i) {
//cout<<"add: "<<add[i].sec<<endl;
while (pos1<=top && add[pos1].fir<=i) s.insert(add[pos1++].sec);
while (pos2<=top && del[pos2].fir<=i) {
//cout<<"del: "<<del[pos].fir<<' '<<del[pos].sec<<endl;
s.erase(s.find(del[pos2++].sec));
}
printf("%d ", s.size()?*s.rbegin():-1);
}
printf("\n"); return 0;
}

题解 Cicada 拿衣服的更多相关文章

  1. 「10.28」Dove 打扑克(链表)·Cicada 与排序(概率)·Cicada 拿衣服(各种数据结构)

    A. Dove 打扑克 考场思考半天线段树树状数组,没有什么想法 打完暴力后突然想到此题用链表实现会很快. 因为只有$n$堆,所以设最多有$x$个不同的堆数,那么$x\times (x-1)/2==n ...

  2. [CSP-S模拟测试]:Cicada拿衣服(暴力+乱搞)

    题目传送门(内部题94) 输入格式 第一行两个整数$n,k$,代表衣服的数量和阈值. 接下来一行$n$个数,第$i$个数$a_i$表示每件衣服的愉悦值. 输出格式 输出一行$n$个数,第$i$个数为$ ...

  3. NOIP 模拟 $36\; \rm Cicada 拿衣服$

    题解 \(by\;zj\varphi\) 发现右端点固定时,左端点的 \(min-max\) 单调递减,且对于 \(or\) 和 \(and\) 相减,最多有 \(\rm2logn\)个不同的值,且相 ...

  4. 20210811 Dove 打扑克,Cicada 与排序,Cicada 拿衣服

    考场 开考感觉 T3 比较可做.T1 看上去不难但毫无思路. 先想了 25min T3,想到一个确定左端点,二分最长的右端点,甚至想到了用猫树维护区间 or and...上厕所回来发现假了,没有单调性 ...

  5. [考试反思]1028csp-s模拟测试91:预估

    这一轮是要闹哪样啊???前十都死活进不去??? 能不能不要到联赛前突然连续掉链子啊!!! 总算难得的切掉了T1.然后又一次把T2和T3的难度估反了 结果给T2剩下了30分钟,想到正解来不及打了. 然后 ...

  6. Noip模拟36 2021.8.11

    刚题的习惯还是改不了,怎么办??? T1 Dove打扑克 考场上打的动态开点线段树+并查集,考后发现自己像一个傻子,并查集就行.. 这几天恶补数据结构疯了 用树状数组维护后缀和,$siz_i$表示编号 ...

  7. csp-s模拟测试91

    csp-s模拟测试91 倒悬吃屎的一套题. $T1$认真(?)分析题意发现复杂度不能带$n$(?),计划直接维护答案,考虑操作对答案的影响,未果.突然发现可以动态开点权值线段树打部分分,后来$Tm$一 ...

  8. noip模拟36

    \(\color{white}{\mathbb{荷花映日,莲叶遮天,名之以:残荷}}\) 今天再次翻车掉出前十 开题看错 \(t1\) 以为操作2的值固定发现是个简单题,然后 \(t2\) 开始大力 ...

  9. 2021.8.11考试总结[NOIP模拟36]

    T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...

随机推荐

  1. 【知识点】H264, H265硬件编解码基础及码流分析

    前言 音视频开发需要你懂得音视频中一些基本概念,针对编解码而言,我们必须提前懂得编解码器的一些特性,码流的结构,码流中一些重要信息如sps,pps,vps,start code以及基本的工作原理,而大 ...

  2. shell 正则表达式一

    正则表达式用于处理文本,精通运用正则表达式可以有效的解决工作的效率 正则表达式有基础正则表达式和扩展正则表达式区别 grep支持基础的正则表达式,grep -E (egrep)支持扩展正则表达式 1. ...

  3. c语言:sprintf() 数字转字符赋值给数组

    //sprintf() //sprintf 最常见的应用之一是把整数打印到字符串中,所以,spritnf 在大多数场合可以替代itoa /* 缓冲区溢出 第一个参数的长度太短了,没的说,给个大点的地方 ...

  4. C语言:监听键盘

    所谓键盘监听,就是用户按下某个键时系统做出相应的处理,本章讲到的输入输出函数也是键盘监听函数的一种,例如 getchar().getche().getch() 等.下面的代码演示了 getche() ...

  5. docker容器技术基础之linux cgroup、namespace

    一.开头 接触过docker的同学多多少少听过这样一句话"docker容器通过linux namespace.cgroup特性实现资源的隔离与限制".今天我们来尝试学习一下这两个东 ...

  6. redis反向代理docker容器中的rabbit mq服务

    最近做的项目中用到了docker,发现docker容器还真挺好用的,可以统一来管理各种资源,项目. 但是在实际使用中就碰到下面这个问题(下面所有的应用都是在docker中启动的): 通过nginx来反 ...

  7. MapReduce处理数据1

    学了一段时间的hadoop了,一直没有什么正经练手的机会,今天老师给了一个课堂测试来进行练手,正好试一下. 项目已上传至github:https://github.com/yandashan/MapR ...

  8. Java基础00-集合进阶26

    1. Collection Collection常用方法详解 1.1 集合知识回顾 1.2 集合类体系结构 集合存储数据的方式有单列和双列 Collection中还有List(可以存储可重复的数据)和 ...

  9. Winform框架中窗体基类的用户身份信息的缓存和提取

    在Winform开发中,有时候为了方便,需要把窗体的一些常规性的数据和操作函数进行封装,通过自定义基类窗体的方式,可以实现这些封装管理,让我们的框架统一化.简单化的处理一些常规性的操作,如这里介绍的用 ...

  10. elementUI的el-input和el-select宽度 一致

    在用vue时,用到了element组件的 el-input 和 el-select(多选框)组件,但是宽度显示不一样,查看了多选框的css,发现element-style是写死的 添加style=&q ...