3月3日
区分度是人吗???第一210,第二130,然后第40+也有100?
喜提 \(100 + 10 + 1 =111 pts\)。
T1
???这放省选第一题?NOIP第二题都不够格。
直接维护向两边分别能跳多远,每次找半径内比当前数大的最小值,简单转移即可。写了颗主席树,复杂度 \(O(n \log n)\)。
点击查看代码
#include <bits/stdc++.h>
char *p1,*p2,buf[1<<21];
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
using namespace std;
const int MAXN=5e5+10;
int n,d,a[MAXN],cnt,b[MAXN];
int L[MAXN],R[MAXN],rot[MAXN];
struct tree{
int cnt;
int ls,rs;
}t[MAXN*35];
void update(int l,int r,int p,int& rt,int rtr)
{
t[rt=++cnt]=t[rtr];
++t[rt].cnt;
if(l==r) return;
int m=(l+r)>>1;
if(p<=m) update(l,m,p,t[rt].ls,t[rtr].ls);
else update(m+1,r,p,t[rt].rs,t[rtr].rs);
}
int ask(int l,int r,int p,int rt,int rtr)
{
if(t[rt].cnt-t[rtr].cnt==0) return 0;
if(l==r) return l;
int m=(l+r)>>1,ans=0;
if(m>p) ans=ask(l,m,p,t[rt].ls,t[rtr].ls);
if(p<r && !ans) ans=ask(m+1,r,p,t[rt].rs,t[rtr].rs);
return ans;
}
int query(int l,int r,int L,int R,int rt,int rtr)
{
if(L<=l && r<=R) return t[rt].cnt-t[rtr].cnt;
int m=(l+r)>>1,ans=0;
if(L<=m) ans=query(l,m,L,R,t[rt].ls,t[rtr].ls);
if(m<R) ans+=query(m+1,r,L,R,t[rt].rs,t[rtr].rs);
return ans;
}
int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
int main()
{
n=read(),d=read();
for(int i=1;i<=n;i++) a[i]=read(),b[a[i]]=i;
for(int i=1;i<=n;i++) update(1,n,a[i],rot[i],rot[i-1]);
for(int i=1;i<=n;i++)
{
int l=max(i-d,1)-1;
int p=ask(1,n,a[i],rot[i],rot[l]);
if(p)
{
L[i]=L[b[p]]+query(1,n,a[i],n,rot[i],rot[b[p]]);
}
}
for(int i=n;i;i--)
{
int r=min(i+d,n);
int p=ask(1,n,a[i],rot[r],rot[i-1]);
if(p)
{
R[i]=R[b[p]]+query(1,n,a[i],n,rot[b[p]-1],rot[i-1]);
}
}
for(int i=1;i<=n;i++) cout<<L[i]+R[i]+1<<" ";
}
T2
赛时无人场切,且赛后发现 std 锅了,应该不是思路的错吧。没改。
T3
赛时仅 jmr 场切,很牛的分拆和推广,好像听懂了,没改。

浙公网安备 33010602011771号