【学习笔记】[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=maxxsnxt(fsx,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) fifront(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];
}
posted @ 2023-02-25 16:44  仰望星空的蚂蚁  阅读(51)  评论(0)    收藏  举报  来源