[APIO 2014] 序列分割
标签:long 一段 http char getch har ble signed 空间复杂度
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=3675
[算法]
首先 , 我们发现将一段序列切成若干段所获得的收益与顺序无关
于是我们可以用fi,j表示切i次 , 前j个数的最大收益
令sumi表示ai的前缀和
显然 , fi,j = max{ fi-1,k + sumk * (sumj - sumk) }
斜率优化即可
此题内存限制较紧 , 可以使用滚动数组优化空间复杂度
时间复杂度 : O(NK)
[代码]
#includeusing namespace std;
#define MAXN 100010
#define MAXK 210
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
int n , k , l , r;
ll X[MAXN] , Y[MAXN] , sum[MAXN] , f[2][MAXN];
int a[MAXN] , q[MAXN] , last[MAXK][MAXN];
template inline void chkmax(T &x,T y) { x = max(x,y); }
template inline void chkmin(T &x,T y) { x = min(x,y); }
template inline void read(T &x)
{
T f = 1; x = 0;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -f;
for (; isdigit(c); c = getchar()) x = (x 3) + (x 1) + c - ‘0‘;
x *= f;
}
int main()
{
read(n); read(k);
for (int i = 1; i )
{
read(a[i]);
sum[i] = sum[i - 1] + a[i];
}
for (int i = 1; i )
{
int now = i & 1 , pre = now ^ 1;
f[now][q[l = r = 1] = 0] = 0;
for (int j = 1; j )
{
while (l 1]] - Y[q[l]] >= -sum[j] * (X[q[l + 1]] - X[q[l]])) ++l;
f[now][j] = Y[q[l]] + X[q[l]] * sum[j];
X[j] = sum[j];
Y[j] = f[pre][j] - sum[j] * sum[j];
last[i][j] = q[l];
while (l 1]]) >= (Y[q[r]] - Y[q[r - 1]]) * (X[j] - X[q[r]])) --r;
q[++r] = j;
}
}
printf("%lld\n" , f[k & 1][n]);
int now = n , s = k;
vectorint > ans;
while (now > 0)
{
now = last[s][now];
if (now) ans.push_back(now);
--s;
}
reverse(ans.begin() , ans.end());
// 输出方案...
return 0;
}
[APIO 2014] 序列分割
标签:long 一段 http char getch har ble signed 空间复杂度
原文地址:https://www.cnblogs.com/evenbao/p/10354216.html
评论