题面与大意
给你几个数
a
i
a_i
ai,要求你给它们分组,每一组(
c
1
∼
c
k
c_1\sim c_k
c1∼ck)的得分为
(
∑
i
=
1
k
c
i
)
2
+
M
(\sum\limits^{k}_{i=1}c_i)^2+M
(i=1∑kci)2+M,其中
M
M
M为常数
求各组得分和最小值
O ( n 2 ) O(n^2) O(n2)做法
橙题水平
强行分段即可
用
s
u
m
sum
sum储存前缀和
方程:
f
i
=
f
j
+
(
s
u
m
i
−
s
u
m
j
)
2
+
M
f_i=f_j+(sum_i-sum_j)^2+M
fi=fj+(sumi−sumj)2+M(1~j,j+1~i分段)
当然,会TLE
优化
转化:
f
i
=
f
j
+
(
s
u
m
i
−
s
u
m
j
)
2
+
M
f_i=f_j+(sum_i-sum_j)^2+M
fi=fj+(sumi−sumj)2+M
f
i
=
f
j
+
s
u
m
i
2
−
2
s
u
m
i
s
u
m
j
+
s
u
m
j
2
+
M
f_i=f_j+{sum_i}^2-2sum_isum_j+{sum_j}^2+M
fi=fj+sumi2−2sumisumj+sumj2+M
f
i
−
s
u
m
i
2
−
M
=
f
j
−
2
s
u
m
i
s
u
m
j
+
s
u
m
j
2
f_i-{sum_i}^2-M=f_j-2sum_isum_j+{sum_j}^2
fi−sumi2−M=fj−2sumisumj+sumj2
2
s
u
m
i
s
u
m
j
+
f
i
−
s
u
m
i
2
−
M
=
f
j
+
s
u
m
j
2
2sum_isum_j+f_i-{sum_i}^2-M=f_j+{sum_j}^2
2sumisumj+fi−sumi2−M=fj+sumj2
y
=
f
j
+
s
u
m
j
2
y=f_j+{sum_j}^2
y=fj+sumj2
k
=
2
s
u
m
i
k=2sum_i
k=2sumi
x
=
s
u
m
j
x=sum_j
x=sumj
b
=
f
i
−
s
u
m
i
2
b=f_i-{sum_i}^2
b=fi−sumi2
代码
注意一点!!!
这个题坑死了!!!
c
i
c_i
ci可能是0的!!
这样的话就会出现
0
0
\frac00
00的情况!!!
遇到这种情况我们直接特判把前面那个点删了就好了
#include<cstdio>
#include<cstring>
inline long long sqr(const long long &a)
{return a*a;}
inline long long min(const long long &a,const long long &b)
{return a<b?a:b;}
using namespace std;
template<typename Tp>
struct deque
{
int head,tail;//head~tail
/*/
Tp list[110];//convinient for debug
deque():head(1),tail(0){}
/*/
Tp *list;//avoid the stack-crashing
deque():head(1),tail(0),list(new int[510000]){}//avoid the stack-crashing
//*/
int size(){return tail-head+1;}
Tp front(){return list[head];}
void push_front(Tp x){list[--head]=x;}
void pop_front(){++head;}
Tp front_2nd(){return list[head+1];}
Tp back(){return list[tail];}
void push_back(Tp x){list[++tail]=x;}
void pop_back(){--tail;}
Tp back_2nd(){return list[tail-1];}
};
int n,m;
long long sum[510000],f[510000];
#define y(j) (f[j]+sqr(sum[j]))
#define k(i) (2*sum[i])
#define x(j) (sum[j])
#define b(i) (f[i]-sqr(sum[i]))
double slope(int a,int b)
{
return (x(a)!=x(b))?
((y(a)-y(b))/(double)(x(a)-x(b))):
1e10;
}
void Main()
{
for(int i=1;i<=n;i++)
scanf("%lld",sum+i),sum[i]+=sum[i-1];
deque<int>q;
f[0]=0;
q.push_back(0);
for(int i=1;i<=n;i++)
{
while(q.size()>1&&slope(q.front(),q.front_2nd())<k(i))q.pop_front();
#define j q.front()
f[i]=f[j]+sqr(sum[i]-sum[j])+m;
while(q.size()>1&&slope(q.back_2nd(),q.back())>slope(q.back(),i))q.pop_back();
q.push_back(i);
}
printf("%lld\n",f[n]);
}
int main()
{
while(~scanf("%d%d",&n,&m))
Main();
return 0;
}