剪裁序列

给定一个长度为 N 的序列 A,要求把该序列分成若干段,在满足“每段中所有数的和”不超过 M 的前提下,让“每段中所有数的最大值”之和最小。
试计算这个最小值

容易得到转移方程:

\[f(i)=\min_{0\le j<i,sum(i)-sum(j) \le m}\{f(j)+ \max_{j+1 \le k \le i} \{ a_k \} \} \]

之后发现: \(f\)有单调性: \(f(i) \le f(i+1)\)

考虑单调性:
j要想成为可能的转移状态: 对于\(j-1\)\(j\)就必须有

\[\max_{j+1 \le k \le i} \{ a_k \} \le \max_{j \le k \le i} \{ a_k \} \]

也就是 \(a_j=\max_{j\le k\le i} \{a_k\}\)

也就是说 如果发现j不满足上述性质 就没有必要把j放入到决策集合
另一方面 如果j满足了上述性质 比j小的决策一定不合理

但是答案不具有单调性 所以要另外开一个优先队列来转移

需要注意的是,当i增大的时候,已经加入set的点要重新更新 这样时间复杂度大
因此 我们利用性质\(\max_{j+1 \le k \le i} \{a_i\}=q_{i+1}\)
这样就能够随着单调队列的更新过程动态更新set里的值

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <cmath>
#define ll long long
using namespace std;
const int N=1e5+10;

template <class T>
T read()
{
	T x=0,f=0,c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return f?-x:x;
}
int a[N],st[N][20];
ll sum[N],f[N];
multiset< ll > s;
deque<int> q;
int n; ll m;
//st(i,j): the max value in [i,i+2^j-1]
void build()
{
	int t=log2(n);
	for(int i=1;i<=n;i++) st[i][0]=a[i];
	for(int j=1;j<=t;j++)
		for(int i=1;i+(1<<j)-1<=n;i++) 
			st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}

int query(int l,int r)
{
	int k=log2(r-l+1);
	return max(st[l][k],st[r-(1<<k)+1][k]);
}

int main()
{
	n=read<int>(); m=read<ll>();
	for(int i=1;i<=n;i++) a[i]=read<int>();
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
	build(); 
	int L=1; ll S=0;	
	for(int i=1;i<=n;i++)
	{
		S+=1ll*a[i];
		while(sum[i]-sum[L-1]>m) L++;
		while(q.size()&&q.front()<L) 
		{
			int t=q.front(); q.pop_front();
			if(q.size()) s.erase(  f[t]+a[q.front()] ) ;
		}
		
		while(q.size()&&a[q.back()]<=a[i]) 
		{
			int t=q.back(); q.pop_back();
			if(q.size()) s.erase( f[q.back()]+a[t] );
		}
	
		if(q.size()) s.insert(f[q.back()]+a[i]); 
		q.push_back(i);
		f[i]=f[L-1]+query(L,i);
		
		if(s.size()) f[i]=min(f[i],*s.begin());
	}

	printf("%d\n",f[n]);
	return 0;
}

技巧:
转移方程中两个式子有不同的单调性
维护决策集合 用数据结构处理

posted @ 2022-02-26 16:58  __iostream  阅读(73)  评论(0)    收藏  举报