NOI ONLINE 2022 提高 游记
Day ?
甚至没报名,蹭隔壁机房题目。
Day 1
先看了下三道题,感觉T1T2都可做,T3不太好做,于是决定顺序开题。
然而被T1卡到心态爆炸,感觉有很多做的方法,但大多数都是假的。深信此题的解法和那个 \(a\) 有关,就疯狂想,导致前半小时基本毫无进展,到一个半小时的时候才决定先打一下其他题的暴力。
之后慢慢开始想到了一些性质,以及一些可能可以有帮助的算法。大概还剩半个小时的时候终于跌跌撞撞的完善了。本来以为是 \(O((n+q)\log n)\) 的,结果假了,就改成 \(O(n^2+q\log n)\) 暴力,大样例太水了,本地只跑了 \(1.3s\) 左右就过了,于是就手捏了一个能卡满的数据验证算法是T的。然后大概就突然想到算法可以优化,于是原来 \(O(n^2)\) 处理的东西直接被我搞成 \(O(n)\) 。结果大样例还是跑了 \(1.3s\) ,但手捏的数据跑过了。
T2没时间想了,考完后发现和正解就差一步了。
好像猜对了T3要用的算法(。
考完后发现T1的一种做法和 \(a\) 基本没关系,用主席树或者离线树状数组做的方法我也想过,但没想到“被卡住的元素”这一想法。反正直接单调栈模拟一遍,然后就是套路题,有点炸心态。
洛谷上T1过了民间数据,然而T3暴力都写萎了。
简述我麻烦复杂的算法:
对每个元素,维护当它是栈底元素时,下一个栈底元素的位置,这样的话再加上倍增,就能愉快地通过。
重点是如何找。显然是两种可能,要么是第一个 \(b\) 比它大的,要么是第一个 \(a\) 和它相同的,且能够弹掉它的。第一种情况直接单调栈,第二种情况可以分析一下性质:栈底上面一个元素的 \(a\) 一定和栈底的不同,所以它的 \(b\) 只要能大于栈顶上面的那个 \(b\) 就可以了。于是暴力枚举 \(a\) 相同的位置,再判断,就是 \(O(n^2)\) 。没有单调性,所以看似不能优化。但发现被忽略过的位置下次还是会被忽略,所以就可以优化了。
不太好写清楚,如果有人想懂啥意思的话可以看代码。好像也有人和我算法差不多。
Day 6
测官方数据,只有 \(80pts\) ,发现优化假了,被所有人吊打。
附录
T1:
#include<bits/stdc++.h>
#define inl inline
#define re(i,x,y) for(int i=(x);i<(y);++i)
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define repp(i,x,y,d) for(int i=(x);i<=(y);i+=(d))
#define reep(i,x,y) for(int i=(x);i<=(y);i<<=1)
#define pe(i,x,y) for(int i=(x);i>(y);--i)
#define per(i,x,y) for(int i=(x);i>=(y);--i)
#define perr(i,x,y,d) for(int i=(x);i>=(y);i-=(d))
#define rep_e(i,u) for(int i=head[(u)];i;i=E[i].nxt)
#define vi vector<int>
#define vL vector<LL>
#define vii vector<pii>
#define viL vector<piL>
#define vLi vector<pLi>
#define vLL vector<pLL>
#define viii vector<tiii>
#define viiL vector<tiiL>
#define viLi vector<tiLi>
#define vLii vector<tLii>
#define viLL vector<tiLL>
#define vLiL vector<tLiL>
#define vLLi vector<tLLi>
#define vLLL vector<tLLL>
#define eb emplace_back
#define pb pop_back
#define mp make_pair
#define mt make_tuple
#define pii pair<int,int>
#define piL pair<int,LL>
#define pLi pair<LL,int>
#define pLL pair<LL,LL>
#define pdi pair<db,int>
#define pdd pair<db,db>
#define pid pair<int,db>
#define tiii tuple<int,int,int>
#define tiiL tuple<int,int,LL>
#define tiLi tuple<int,LL,int>
#define tLii tuple<LL,int,int>
#define tiLL tuple<int,LL,LL>
#define tLiL tuple<LL,int,LL>
#define tLLi tuple<LL,LL,int>
#define tLLL tuple<LL,LL,LL>
#define lowbit(x) ((x)&(-(x)))
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double db;
#define getchar() (SB==TB&&(TB=(SB=BB)+fread(BB,1,1<<15,stdin),SB==TB)?EOF:*SB++)
char BB[1<<16],*SB=BB,*TB=BB;
template<typename T>void read(T &n){
T w=1;n=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){n=(n<<3)+(n<<1)+(ch&15);ch=getchar();}
n*=w;
}
template<typename T>inl void exg(T &a,T &b){ (a^b)&&(a^=b^=a^=b); }
template<typename T>inl void chkmn(T &a,const T &b){ (a>b)&&(a=b); }
template<typename T>inl void chkmx(T &a,const T &b){ (a<b)&&(a=b); }
inl int min(const int &a,const int &b){ return a<b?a:b; }
inl int max(const int &a,const int &b){ return a>b?a:b; }
inl LL min(const LL &a,const LL &b){ return a<b?a:b; }
inl LL max(const LL &a,const LL &b){ return a>b?a:b; }
int MOD;
inl int adt(const int &a){ return (a%MOD+MOD)%MOD; }
inl int inc(const int &a,const int &b){ return a+b>=MOD?a+b-MOD:a+b; }
inl int dec(const int &a,const int &b){ return a-b<0?a-b+MOD:a-b; }
inl int mul(const int &a,const int &b){ return 1LL*a*b%MOD; }
inl int sqr(const int &a){ return 1LL*a*a%MOD; }
inl int cub(const int &a){ return 1LL*a*a%MOD*a%MOD; }
inl void Adt(int &a){ a=(a%MOD+MOD)%MOD; }
inl void Inc(int &a,const int &b){ ((a+=b)>=MOD)&&(a-=MOD); }
inl void Dec(int &a,const int &b){ ((a-=b)<0)&&(a+=MOD); }
inl void Mul(int &a,const int &b){ a=1LL*a*b%MOD; }
inl void Sqr(int &a){ a=1LL*a*a%MOD; }
inl void Cub(int &a){ a=1LL*a*a%MOD*a%MOD; }
inl int fsp(int a,int x=MOD-2){
int res=1;
while(x){
if(x&1) Mul(res,a);
Sqr(a),x>>=1;
}return res;
}
const int maxn=5e5+5;
int n,q,top;
int ans[5005][5005];
int a[maxn],b[maxn],stk[maxn],c[maxn],d[maxn],lo[maxn];
int mx[19][maxn],nxt[19][maxn];
int main(){
freopen("stack.in","r",stdin);
freopen("stack.out","w",stdout);
read(n),read(q),lo[0]=-1;
rep(i,1,n) read(a[i]),lo[i]=lo[i>>1]+1;
rep(i,1,n) read(b[i]),mx[0][i]=b[i];
rep(i,1,18) rep(j,1,n-(1<<(i-1))+1) mx[i][j]=max(mx[i-1][j],mx[i-1][j+(1<<(i-1))]);
auto Query=[&](int l,int r){
if(r<l) return 0;
int L=lo[r-l+1];
return max(mx[L][l],mx[L][r-(1<<L)+1]);
};
if(n<=5000){
rep(i,1,n){
top=0;
rep(j,i,n){
while(top&&(a[j]==a[stk[top]]||b[j]>=b[stk[top]])) --top;
ans[i][j]=ans[i][j-1];
if(!top) ++ans[i][j];
stk[++top]=j;
}
}
int l,r;
while(q--){
read(l),read(r);
printf("%d\n",ans[l][r]);
}
}
else{
rep(i,1,n) d[i]=n+1;
per(i,n,1) c[i]=d[a[i]],d[a[i]]=i;
per(i,n,1){
while(top&&b[i]>b[stk[top]]) --top;
if(top) nxt[0][i]=stk[top];
else nxt[0][i]=n+1;
int las=i,p=c[i],mx=0,g=n+1;
while(p<=nxt[0][i]&&p!=n+1){
chkmx(mx,Query(las+1,p-1));
if(b[p]>=mx){
g=nxt[0][i]=p;
break;
}
las=p,p=c[p];
}
p=c[i];
while(p!=g){
int x=c[p];
c[p]=g;
p=x;
}
stk[++top]=i;
}
nxt[0][n+1]=n+1;
rep(i,1,18) rep(j,1,n+1) nxt[i][j]=nxt[i-1][nxt[i-1][j]];
int l,r;
while(q--){
read(l),read(r);
int ans=0;
per(i,18,0) if(nxt[i][l]<=r) l=nxt[i][l],ans|=1<<i;
printf("%d\n",ans+1);
}
}
return 0;
}
T2T3暴力就懒得贴了。

浙公网安备 33010602011771号