题意
n个物品,划成k个连续段,每一段的贡献是这个区间最大的数,对k从1~n求最小和最大的贡献。
分析
题意很简单,首先看最大贡献,最大贡献就是划的时候,把大的数尽量不在一个段里就可以了。即从大往小加起来。
接下来看最小贡献,最小贡献很显然有一个的dp转移,我们记为前i个数分成j段的最小代价,于是有,这里n是8000,
的转移我们无法接受,于是考虑优化。
通过观察我们发现对于i来说, 可以分为两种情况,j作为当前最后一段的最大值,或者不是最大值。
i不是最大值,那我们考虑前面比大的离他最近的数,我们发现是一个可以被接受的状态,从k+1~i之间的所有数直接挂到k所在区间即可,更之前的数同样不需要考虑,因为我们总是满足i,k同区间。
接下来考虑i是最大值,即i,k不同区间的情况,这一段似乎只能枚举,但是考虑到不是最大值的时候我们可以使用单调栈来维护信息,那么这里我们只需要在单调栈里再加一维,记录单调栈内两个数之间的最小的即可。
下面代码
//#include<algorithm>
//#include<bitset>
//#include<cassert>
//#include<cctype>
//#include<chrono>
//#include<cmath>
//#include<cstdio>
//#include<cstring>
//#include<functional>
//#include<iomanip>
//#include<iostream>
//#include<map>
//#include<queue>
//#include<random>
//#include<set>
//#include<sstream>
//#include<stack>
//#include<string>
//#include<unordered_map>
//#include<utility>
//#include<vector>
//#include<memory.h>
#include<bits/stdc++.h>
#define rep(i,a,b) for(auto i=(a);i<=(b);++i)
#define per(a,b) for(auto i=(a);i>=(b);--i)
#define pb push_back
#define pii pair<int,int>
#define pll pair<long long,long long>
#define db double
#define IL inline
#define fir first
#define sec second
#define eps (1e-10)
#define mkp make_pair
//#define rep((a),(b)) for(int i=(a);i<=(b);++i)
#define lowbit(x) (x&(-x))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const int dx[8]={0,1,0,-1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
const ll mod=998244353;//1e9+7;
const int N=1e4+10,M=4e4+10;
ll qpow(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll gcd(ll a,ll b)
{
if(b)return gcd(b,a%b);
return a;
}
int n;
ll a[N];
ll dp[2][N];
ll ans[N][2];
void solve()
{
int n;cin>>n;
vector<int>b;
for(int i=1;i<=n;++i)cin>>a[i],b.push_back(a[i]);
sort(b.begin(),b.end(),greater<int>());
for(int i=0;i<n;++i)
{
ans[i+1][1]=ans[i][1]+b[i];
}
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for(int j=1;j<=n;++j)
{
stack<pair<int,ll> >st;
for(int i=j;i<=n;++i)
{
ll w=LINF,v=LINF;
w=dp[(j-1)&1][i-1];
while(!st.empty()&&a[st.top().first]<a[i])
{
w=min(w,st.top().second);
st.pop();
}
if(st.empty())
{
if(i==1)w=0;
}
else
{
v=dp[j&1][st.top().first];
}
st.push({i,w});
dp[j&1][i]=min(w+a[i],v);
}
ans[j][0]=dp[j&1][n];
}
for(int i=1;i<=n;++i)cout<<ans[i][0]<<' '<<ans[i][1]<<'\n';
}
int main()
{
IOS;
int T=1;
// init();
// cin>>T;
// scanf("%d",&T);
// read(T);
while(T--)solve();
return 0;
}
/*\
100 200
7 15 8
*/