Description
Given an integer sequence { an } of length N, you are to cut the sequence into several parts every one of which is a consecutive subsequence of the original sequence. Every part must satisfy that the sum of the integers in the part is not greater than a given integer M. You are to find a cutting that minimizes the sum of the maximum integer of each part.
Input
The first line of input contains two integer N (0 < N ≤ 100 000), M. The following line contains N integers describes the integer sequence. Every integer in the sequence is between 0 and 1 000 000 inclusively.
Output
Output one integer which is the minimum sum of the maximum integer of each part. If no such cuttings exist, output −1.
思路
就问为什么STL会TLE,手打双端队列就300+ms
设f[i]为前i个的最优取值,那么f[n]一定要从f[n-1]~f[0]中转移过来 这不是废话吗
那么相当于选择一个切口,把1n分成2部分:$1至i,i+1至n$,显然,1i的部分已经计算出来了,而i+1 ~n的部分不能>m,那么我们用一个单调队列来维护所有可能的切口
code:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<deque>
#include<cstdio>
#include<map>
using namespace std;
long long a[100001];
long long f[100001],s[100001];
long long mx,t,v,r,c,b,x,l,j,k;
long long n,p,q,i,m;
void read(long long& x)
{
x=0;
long long f=1;
char ch=getchar();
while (!isdigit(ch)) (ch=='-')&&(f=-1),ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
x*=f;
}
void wr(long long x)
{
(x<0)&&(x=-x,putchar('-'));
if (x>9) wr(x/10);
putchar(x%10^48);
}
int main()
{
read(n),read(m);
for (i=1;i<=n;i++)
{
read(s[i]);
if (s[i]>m)
{
printf("-1");
return 0;
}
}
l=1;
for (i=1;i<=n;i++)
{
while (l<=r&&s[a[r]]<=s[i]) r--;
a[++r]=i;
k+=s[i];
while (k>m) k-=s[++b];
while (l<=r&&a[l]<=b) l++;
f[i]=0x7f7f7f7f;
v=b;
for (j=l;j<=r;j++)
{
if (f[i]>f[v]+s[a[j]]) f[i]=f[v]+s[a[j]];
v=a[j];
}
}
wr(f[n]);
return 0;
}