把i看成j了,佛系debug一晚上,感觉越来越菜了
题意:
给出N个单词,每个单词有个非负权值Ci,现在要将它们分成连续的若干段,每段的代价为此段单词的权值和的平方,还要加一个常数M,,即。现在想求出一种最优方案,使得总费用之和最小。
分析:
- 注意一开始0要入队
- 注意斜率的比较不能用double,要交叉相乘,考虑到分母不为零
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
const ll mod = 1e9 + 7;
const int maxn = 5e5 + 10;
const int inf = 0x3f3f3f3f;
int n, m;
int dp[maxn], q[maxn];
int sum[maxn];
int head, tail;
int sq(int n)
{
return n * n;
}
int getdp(int i, int j)
{
return dp[j] + sq(sum[i] - sum[j]) + m;
}
int getup(int i, int j)
{
return dp[i] + sq(sum[i]) - dp[j] - sq(sum[j]);
}
int getdown(int i, int j)
{
return 2 * (sum[i] - sum[j]);
}
int main()
{
while(scanf("%d%d", &n, &m) == 2)
{
for(int i=1;i<=n;i++)
scanf("%d",&sum[i]);
sum[0]=dp[0]=0;
for(int i=1;i<=n;i++)
sum[i]+=sum[i-1];
head=tail=0;
q[tail]=0;
for(int i = 1; i <= n; i++)
{
while(head<tail && getup(q[head+1],q[head])<=sum[i]*getdown(q[head+1],q[head]))
head++;
dp[i]=getdp(i,q[head]);
while(head<tail && getup(i,q[tail])*getdown(q[tail],q[tail-1])<=getup(q[tail],q[tail-1])*getdown(i,q[tail]))
tail--;
q[++tail]=i;
}
cout << dp[n] << endl;
}
}