海亮寄 7.8
前言
业精于勤荒于嬉,行成于思毁于随
正文(模拟赛)
卦象:大凶
模拟赛原题来源:COCI 2023
吐槽:我的补题时间呢???为什么要加一场模拟赛???本来想熬会夜学一下点分治的,教练组整这出???
(总有地上的生灵,敢于直面雷霆的威光服从教练组的安排)
感受:是 IOI 赛制,\(3\) 个小时 \(5\) 道题,分数 \(400/500\)。早上起来整个人的精神状态并不是特别好,有点晕,大脑可能没有完全开机。T1 人口普查,打字速度慢注定了没有拿到一血。隔壁墨鱼软软二人组在云落提交 T1 的时候,已经先后切掉 T1 和 T2 了,悲。后来开 T2,15 min 解决第二道人口普查题的代码。然而没有判断 corner case,一直处于 WA 的状态。瞪眼 20 min 无果,内心挣扎一会后大踏步地走向 T3,一眼不可做题,掉头走向 T4。T4 总感觉自己以前刷题刷到过类似的题目,所以很快有了正解的思路。这时候老师提示大家 T3 可能略有难度,建议优先开后面两道题目。听到老师的播报,只能说喜忧参半。喜是因为这证明了若干分钟以前放弃 T3 的决策是正确的。忧是因为许多人(包含绝大多数小登)都解决了前两题,然而云落依旧是可怜的 116pts。平复心情后,秒 T4,回去重构 T2,再切 T2。以上操作在 40min 内完成,算是追上了平均线。剩余 80 min 开 T5,审错题以为是分块板子题,上来就是一套根号组合拳。结果漏看一个条件,浪费 30 min。本来想打暴力的,因为 T3 和 T5 的暴力分数一共 114 分,性价比相当高。但注意到 T5 的特殊性质,突然灵光一闪,离线扫描线剩下的就是线段树板子。于是就有点贪了,想要 164 pts(T5 正解 + T3 暴力)。理想是丰满的,现实是骨感的。rz 线段树板子调了 40 min,原因是区间合并的重载运算符写锅了,和线段树建树部分初始化错误,最后遗憾只剩余 10 min 罚坐时间。总而言之,切了四个题,但是心惊胆战的,没有一个拿一血。并且最后有一点点决策失误,略有遗憾叭!
T1
人口普查,枚举雪花中心即可,需要了解反斜杠的表达方式是 '\\'
T2
人口普查 \(\times 2\),广搜板子题
赛时前段可能不咋清醒,没有判无解的情况,后来重构后就 A 掉了
T3
机房里两个用脚维护的 dalao,一个树套树,一个 CDQ
STO 软软 & 火腿肠 Orz !!!
用的是老师讲题时的解法,没有用脚,开发大脑
由题意,有以下几点
- 题意等价转化为求
-
对于一个后缀 \(\min\) 值,其对答案的贡献是 \(i-a_i\)
-
一个元素成为后缀 \(\min\) 的时间,充要转化为在它后面且比它小的数消失时间的 \(\max\) 值(经典二维偏序问题,离线扫描线维护)
根据以上三点,大体流程就出来了
我们需要动态维护 \(i,a_i\) 以及提前离线预处理出成为后缀 \(\min\) 的时间
考虑一轮操作后如何计算答案
删除部分存在两种情况
-
删除后缀 \(\min\),则剔除该后缀 \(\min\) 给的贡献
-
删除非后缀 \(\min\),会对该元素以后的所有后缀 \(\min\) 造成贡献 \(-1\) 的操作
第一点是好做的(用 set 维护后缀 \(\min\) 值,lower_bound 查一下即可)
第二点需要动态维护一个元素后的后缀 \(min\) 个数
然后是计算与更新部分
可以根据已经处理出的元素成为后缀 \(\min\) 的时间表来完成贡献计算,计算式还是经典的 \(i-a_i\)
感觉可能细节较多,给一份丑陋的代码实现:
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
#define vi vector<int>
#define pb push_back
#define lwbd lower_bound
using namespace std;
const int N=1e5+5;
int n,Q,a[N],q[N],tim[N];vi vec[N];
set<pii> S;
bool vis[N],mrk[N];
struct BIT{
int c[N];
inline int lb(int x){return x&(-x);}
inline void add(int x,int v){
for(int i=x;i<=n;i+=lb(i))c[i]+=v;
return;
}
inline int ask(int x){
int res=0;
for(int i=x;i;i-=lb(i))res+=c[i];
return res;
}
inline int qry(int l,int r){return ask(r)-ask(l-1);}
}bit1,bit2,bit3;
struct Segment_Tree{
struct node{int l,r,mx;}tr[N<<2];
inline void pushup(int u){
tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx);
return;
}
inline void build(int u,int l,int r){
tr[u].l=l,tr[u].r=r;
if(l==r){tr[u].mx=0;return;}
int mid=(l+r)>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
return;
}
inline void modify(int u,int pos,int v){
int l=tr[u].l,r=tr[u].r;
if(l==r){tr[u].mx=v;return;}
int mid=(l+r)>>1;
if(pos<=mid)modify(u<<1,pos,v);
else modify(u<<1|1,pos,v);
pushup(u);
return;
}
inline int query(int u,int ql,int qr){
int l=tr[u].l,r=tr[u].r;
if(ql<=l&&qr>=r)return tr[u].mx;
int mid=(l+r)>>1,res=0;
if(ql<=mid)res=max(res,query(u<<1,ql,qr));
if(qr>mid)res=max(res,query(u<<1|1,ql,qr));
return res;
}
}sgt;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>Q;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)tim[i]=Q+1;
for(int i=1;i<=Q;i++){cin>>q[i];tim[q[i]]=i;}
sgt.build(1,1,n);
for(int i=n;i>=1;i--){
int x=sgt.query(1,1,a[i]-1);
vec[x].pb(i);
sgt.modify(1,a[i],tim[i]);
}
S.insert(mkp(0,0)),S.insert(mkp(n+1,n+1));
int sum=0;
for(int i:vec[0]){
bit3.add(i,1);vis[i]=true;S.insert(mkp(a[i],i));
sum+=(i-a[i]);
}
cout<<sum+n<<' ';
for(int i=1;i<=n;i++)bit1.add(i,1),bit2.add(a[i],1);
for(int i=1;i<=Q;i++){
// del
mrk[q[i]]=true;
if(!vis[q[i]])sum-=(bit3.qry(q[i]+1,(--S.lwbd({a[q[i]],0}))->se));
else{
bit3.add(q[i],-1);
S.erase(mkp(a[q[i]],q[i]));
sum-=(bit1.ask(q[i])-bit2.ask(a[q[i]]));
}
bit1.add(q[i],-1),bit2.add(a[q[i]],-1);
// cal
for(int x:vec[i]){
if(mrk[x])continue;
bit3.add(x,1);vis[x]=true;S.insert({mkp(a[x],x)});
sum+=(bit1.ask(x)-bit2.ask(a[x]));
}
cout<<sum+(n-i)<<' ';
}
cout<<'\n';
return 0;
}
T4
做过类似的博弈论题,也做过类似的区间结构题,正解基本上呼之欲出
记 \(f_{l,r}\) 表示两人对区间 \([l,r]\) 进行游戏的最大分数差,容易发现转移形如决策一个边界条件。首先 \(a_l\)(或者 \(a_r\))先判断是否可以加分,其次再判断能否拉开分数差
(其实观察性质发现,分数差总是 \(0/1\)?,这个结论是瞎猜的,未必正确)
那么一开始统计处分数和,在结合 \(f_{1,n}\),就可以分别求出先后手的分数了
T5
读错题 \(+\) 选用错误的算法 \(+\) 正确代码的降智错误
全局查询已经提示我们离线扫描线了,容易发现按海平面上升顺序扫描线并不好做(极长连续段计数问题不好撤销),所以考虑按海平面下降顺序扫描线。
《线段树随便维护即可》
小结
学 T3 去咯!明天休息一天!好耶!
Upd. 诶?明天休息半天?不耶……
后记
世界孤立我任它奚落
完结撒花!

浙公网安备 33010602011771号