HDU 3507 Print Article

题面与大意

给你几个数 a i a_i ai,要求你给它们分组,每一组( c 1 ∼ c k c_1\sim c_k c1ck)的得分为 ( ∑ i = 1 k c i ) 2 + M (\sum\limits^{k}_{i=1}c_i)^2+M (i=1kci)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+(sumisumj)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+(sumisumj)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+sumi22sumisumj+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 fisumi2M=fj2sumisumj+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+fisumi2M=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=fisumi2

代码

注意一点!!!
这个题坑死了!!!
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值