【学习笔记】[ARC150F] Constant Sum Subsequence
第一眼看上去,这道题一点都不套路
第二眼看上去,大概是要考
d
p
dp
dp优化,那没事了,除非前面
3
3
3道题都做完了否则直接做这道题肯定很亏
首先我们要定义一个好的状态。废话
设 f s f_{s} fs表示 B B B序列的和为 s s s时,能达到的 A A A序列的最大长度,也就是最紧的限制。
这一步定义非常自然,到这里都没有任何问题
不过直接暴力转移复杂度 O ( S 2 log n ) O(S^2\log n) O(S2logn),考场上好像只能得到 20 p t s 20pts 20pts。
似乎有根号乱搞的做法,但是这道题
n
n
n,
S
S
S比较大所以会被卡掉
这是逼着我们想正解啊
不管了,根号乱搞比较好想,而且确实也是考场上性价比最高的做法
cdq
\text{cdq}
cdq分治的想法挺阳间的,应该可以学一下
乱胡一下吧,不过考场上可能我也不会写 考虑计算区间
[
l
,
r
]
[l,r]
[l,r]的
d
p
dp
dp值,显然我们知道转移的这个数不会超过
[
l
,
r
]
[l,r]
[l,r]这个区间的长度。
发挥
bot
\text{bot}
bot的能力 我们有转移式
f
s
=
max
x
≤
s
nxt
(
f
s
−
x
,
x
)
f_s=\max_{x\le s}\text{nxt}(f_{s-x},x)
fs=maxx≤snxt(fs−x,x),并且
f
s
f_s
fs是单增的,因此
∀
i
∈
[
m
i
d
+
1
,
r
]
,
f
i
>
f
m
i
d
\forall i\in [mid+1,r],f_i>f_{mid}
∀i∈[mid+1,r],fi>fmid。先枚举一个
x
x
x,则我们只需要考虑可能对右区间有贡献的
s
s
s,即满足
nxt
(
f
s
,
x
)
=
nxt
(
f
m
i
d
,
x
)
\text{nxt}(f_{s},x)=\text{nxt}(f_{mid},x)
nxt(fs,x)=nxt(fmid,x)。不难猜想,这些
s
s
s 形成了一个区间,并且这个区间的左端点就是最小的
i
i
i满足
f
i
≥
front
(
f
m
i
d
,
x
)
f_i\ge \text{front}(f_{mid},x)
fi≥front(fmid,x),于是对于这个区间,贡献是相同的,而对应的右半部分下标是连续的,因此用一个线段树维护即可。
复杂度两个
log
\log
log。应该可以通过吧?
代码先咕了
似乎代码也不是特别长,出题人还是挺良心的
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define fi first
#define int ll
#define se second
using namespace std;
const int N=2e5+5;
const int M=2e6+5;
int n,S,a[M],f[N],t[N<<2];
vector<int>v[N];
int nxt(int x,int y){
int z=x%n;if(!z)z=n;
int p=upper_bound(v[y].begin(),v[y].end(),z)-v[y].begin();
if(p==v[y].size())return x+v[y][0]-z+n;
return x+v[y][p]-z;
}
int pre(int x,int y){
int z=x%n;if(!z)z=n;
int p=upper_bound(v[y].begin(),v[y].end(),z)-v[y].begin()-1;
if(~p)return x-z+v[y][p];
return x-z+v[y].back()-n;
}
void upd(int p,int l,int r,int ql,int qr,int x){
if(ql<=l&&r<=qr){
t[p]=max(t[p],x);
return;
}
int mid=l+r>>1;
if(ql<=mid)upd(p<<1,l,mid,ql,qr,x);
if(mid<qr)upd(p<<1|1,mid+1,r,ql,qr,x);
}
int qry(int p,int l,int r,int x){
if(l==r)return t[p];
int mid=l+r>>1;
if(x<=mid)return max(qry(p<<1,l,mid,x),t[p]);
return max(qry(p<<1|1,mid+1,r,x),t[p]);
}
void solve(int l,int r){
if(l==r){
f[l]=max(f[l],qry(1,1,S,l));
return;
}
int mid=l+r>>1;
solve(l,mid);
for(int i=1;i<=r-l+1;i++){
int L=lower_bound(f+l,f+mid+1,pre(f[mid],i))-f;
assert(L<=mid);
L=max(mid+1,L+i);int R=min(mid+i,r);
if(L<=R){
upd(1,1,S,L,R,nxt(f[mid],i));
}
}
solve(mid+1,r);
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>S;
for(int i=1;i<=n;i++)cin>>a[i],v[a[i]].pb(i);
for(int i=1;i<=S;i++)f[i]=nxt(0,i);
solve(1,S);
cout<<f[S];
}

浙公网安备 33010602011771号