版权声明:欢迎大家转载,转载请标明出处。 https://blog.csdn.net/ylsoi/article/details/82763387
题目大意:
你正在玩一个关于长度为 n 的非负整数序列的游戏。这个游戏中你需要把序列分成 k+1 个非空的块。为了得到 k+1块,你需要重复下面的操作 k 次:
选择一个有超过一个元素的块(初始时你只有一块,即整个序列)
选择两个相邻元素把这个块从中间分开,得到两个非空的块。
每次操作后你将获得那两个新产生的块的元素和的乘积的分数。你想要最大化最后的总得分。
思路:
不难发现操作的顺序其实并没有影响,最后的答案就是不在同一个块内的元素乘积之和。
于是考虑dp:
直接DP是
的,于是把它展开,发现可以得到斜率式:
斜率不断递增,应使截距尽量小,即维护一个下凸壳
又因为横坐标不断增大,用单调队列维护即可。
注意一些细节。决策点会有横坐标相同的的,直接把斜率设为正无穷就好了,因为这样可以保证后面的点将这些点弹掉。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
typedef long long ll;
using namespace std;
void File(){
freopen("uoj104.in","r",stdin);
freopen("uoj104.out","w",stdout);
}
template<typename T>void read(T &_){
T __=0,mul=1; char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')mul=-1;
ch=getchar();
}
while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
_=__*mul;
}
template<typename T>void write(T x,char ch){
if(!x){putchar('0');putchar(ch);return;}
if(x<0)putchar('-'),x=-x;
ll y=10,len=1;
while(y<=x)y=(y<<1)+(y<<3),++len;
while(len--){
y/=10;
putchar(x/y+48);
x%=y;
}
putchar(ch);
}
const int maxn=1e5+10;
const int maxk=200+10;
const ll inf=LLONG_MAX>>1;
int n,m,pre[maxk][maxn],ans[maxn];
ll a[maxn],dp[maxn],s[maxn],sq[maxn];
void init(){
read(n); read(m);
REP(i,1,n)read(a[i]),s[i]=s[i-1]+a[i],sq[i]=s[i]*s[i];
}
struct node{
ll x,y;
int id;
}qu[maxn];
node getnode(int p){return (node){s[p],sq[p]-dp[p],p};}
double getk(node aa,node bb){
if(aa.x==bb.x)return inf;
return (double)(aa.y-bb.y)/(aa.x-bb.x);
}
void work(){
REP(k,1,m){
ll val;
int head=0,tail=1;
qu[++head]=getnode(k);
REP(i,k+1,n){
while(head<tail && getk(qu[head],qu[head+1])<s[i])++head;
val=s[i]*qu[head].x-qu[head].y;
pre[k][i]=qu[head].id;
node t=getnode(i);
dp[i]=val;
while(head<tail && getk(qu[tail],t)<getk(qu[tail-1],qu[tail]))--tail;
qu[++tail]=t;
}
}
write(dp[n],'\n');
int p=n;
DREP(i,m,1)p=pre[i][p],ans[i]=p;
REP(i,1,m)write(ans[i],' ');
}
int main(){
File();
init();
work();
//cerr<<(double)clock()/CLOCKS_PER_SEC<<endl;
return 0;
}