P2048 [NOI2010] 超级钢琴

首先前 \(k\) 大考虑 shopping plans trick。

考虑设计状态 \(S\) 满足:

· 每个子段被唯一的状态 \(S\) 表示。

· \(w(S'\in nxt(S))\le w(S)\)

· \(pre(S)\) 唯一。

堆维护最优状态即可。

因为存在负数,所以以子段端点 \(l,r\) 拓展状态没有前途,因为无法保证后继权值小于当前状态权值。先将子段和转化为 \(sum_r-sum_{l-1}\),因为初始时需要权值最大的状态,考虑 \((l,k)\) 表示子段以 \(l\) 为左端点,其权值为 \(\max_k(sum:[l+L-1,l+R-1])-sum_{l-1}\),初始状态即为所有 \((l,1),l\le n-L+1\)。有了状态拓展是简单的,因为要求唯一表示,故 \((l,k)\)\(l\) 必定不变,转移只有 \((l,k)\to (l,k+1)\),于是就是求区间静态第 \(k\) 小,主席树维护即可,时间复杂度 \(O(k\log n)\),空间复杂度 \(O(n\log (n\cdot V))\)

拜读题解后有更加优秀的将状态改为 \((l,l',r')\) 表示子段以 \(l\) 为左端点,其权值为 \(\max (sum:[l',r'])-sum_{l-1}\) 则每次转移形容分裂一个区间求两边的最值,容易 st 表维护,空间复杂度 \(O(n\log n)\)

Takanashi Rikka
#include<bits/stdc++.h>
using namespace std;
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define il inline
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
inline void cmx(auto &x,ll y){if(y>x)x=y;}
inline void cmn(auto &x,ll y){if(y<x)x=y;}
inline int max(vector<int>w){int res=-1e9;for(int i:w)cmx(res,i);return res;}
#define pcount(x) __builtin_popcount(x)
const int N=5e5+5,V=1000;
#define int ll
int tot,rt[N],a[N],s[N],n,k,L,R,ans;
struct node{int ls,rs,x;}t[N<<6];
void pushup(int u){t[u].x=t[t[u].ls].x+t[t[u].rs].x;}
void upd(int &id,int idx,int l,int r,int x){
	if(!id||id==idx)t[id=++tot]=t[idx];
	if(l==r)return ++t[id].x,void();
	int mid=l+r>>1;
	if(x<=mid)
		 upd(t[id].ls,t[idx].ls,l,mid,x);
	else upd(t[id].rs,t[idx].rs,mid+1,r,x);
	pushup(id);
}
int query(int id,int idx,int l,int r,int k){
	if(l==r)return l;
	int mid=l+r>>1;
	if(t[t[id].rs].x-t[t[idx].rs].x>=k)
		 return query(t[id].rs,t[idx].rs,mid+1,r,k);
	else return query(t[id].ls,t[idx].ls,l,mid,k-t[t[id].rs].x+t[t[idx].rs].x);
}
int ask(int l,int r,int k){
	if(k>r-l+1)return -1e18;
	return query(rt[r],rt[l-1],-V*n,V*n,k);
}
struct state{
	int l,k,sum;
	friend bool operator<(state x,state y){
		return x.sum<y.sum;
	}
};priority_queue<state>dl;
void UesugiErii(){
	cin>>n>>k>>L>>R;
	for(int i=1;i<=n;i++)cin>>a[i],s[i]=s[i-1]+a[i];
	for(int i=1;i<=n;i++)upd(rt[i],rt[i-1],-V*n,V*n,s[i]);
	for(int i=1;i<=n-L+1;i++)
		dl.push({i,1,ask(i+L-1,min(n,i+R-1),1)-s[i-1]});
	while(!dl.empty()&&(k--)){
		state u=dl.top();dl.pop();ans+=u.sum;
		// cerr<<u.l<<' '<<u.k<<' '<<u.sum<<'\n';
		dl.push({u.l,u.k+1,ask(u.l+L-1,min(n,u.l+R-1),u.k+1)-s[u.l-1]});
	}
	cout<<ans;
}
signed main(){
	//IO();//cfast;
	int _=1;//cin>>_;
	for(;_;_--)UesugiErii();
	return 0;
}
posted @ 2026-01-14 20:00  Uesugi1  阅读(2)  评论(0)    收藏  举报