BZOJ4518「SDOI2016」征途

传送门


SOL

tips
方差:
在这里插入图片描述

方程:
f [ m ] [ n ] f[m][n] f[m][n]:第m天在n点的 方差*m^2 的最小值
P [ m ] [ n ] P[m][n] P[m][n]第m天在n点的 分成 m份的 平方和的 最小值
( a 1 2 + a 2 2 + . . . + a n 2 a_1^2+a_2^2+...+a_n^2 a12+a22+...+an2)

f 有:
f [ d ] [ i ] = d ∗ P [ d − 1 ] [ j ] + d ∗ ( s u m [ i ] − s u m [ j ] ) 2 − s u m [ i ] 2 f[d][i]=d*P[d-1][j]+d*(sum[i]-sum[j])^2-sum[i]^2 f[d][i]=dP[d1][j]+d(sum[i]sum[j])2sum[i]2
变形:
2 ∗ d ∗ s u m [ i ] ∗ s u m [ j ] + f [ d ] [ i ] − . . . = d ∗ ( s u m [ j ] 2 + P [ d − 1 ] [ j ] ) 2*d*sum[i] * sum[j] + f[d][i] -... =d*(sum[j]^2+P[d-1][j]) 2dsum[i]sum[j]+f[d][i]...=d(sum[j]2+P[d1][j])
同时除以d

2 ∗ s u m [ i ] ∗ s u m [ j ] + f [ d ] [ i ] / d − . . . = s u m [ j ] 2 + P [ d − 1 ] [ j ] 2*sum[i]*sum[j]+f[d][i]/d-...=sum[j]^2+P[d-1][j] 2sum[i]sum[j]+f[d][i]/d...=sum[j]2+P[d1][j]

···············································································································································
P有:

P [ d ] [ i ] = ( s u m [ i ] − s u m [ j ] ) 2 + P [ d − 1 ] [ j ] P[d][i]= (sum[i]-sum[j])^2+ P[d-1][j] P[d][i]=(sum[i]sum[j])2+P[d1][j]
变形:
2 ∗ s u m [ i ] ∗ s u m [ j ] + P [ d ] [ i ] − . . . = P [ d − 1 ] [ j ] + s u m [ j ] 2 2*sum[i] * sum[j] + P[d][i] -... = P[d-1][j]+sum[j]^2 2sum[i]sum[j]+P[d][i]...=P[d1][j]+sum[j]2
发现计算 (P) 和 (f)的斜率式子的 x , y , k都是相同的,

所以 P的最优决策点就是 f 的 最优决策点,

处理完P之后直接用停在 head 的 点 求就可以了


CODE

#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define db double
const int N=3e3+5;

ll P[N][N];
int sum[N],q[N],head,tail,n,m;
/*
	f[d][i]=d*P[d-1][j]+d*(sum[i]-sum[j])^2-sum[i]^2
	2*d*sum[i] * sum[j] + f[d][i] -... =d*(sum[j]^2+P[d-1][j])                  			  
  	 
	2*sum[i]*sum[j]+f[d][i]/d-...=sum[j]^2+P[d-1][j];

  	
	P[d][i]=  (sum[i]-sum[j])^2+ P[d-1][j]
  	2*sum[i] * sum[j] + P[d][i] -... =  P[d-1][j]+sum[j]^2
   
*/
inline db slope(int a,int b,int d){return 1.00*(sum[a]*sum[a]-sum[b]*sum[b]+P[d-1][a]-P[d-1][b])/(1.00*(sum[a]-sum[b]));}
signed main(){
	sf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)sf("%d",&sum[i]),sum[i]+=sum[i-1],P[1][i]=sum[i]*sum[i];
	for(int d=2;d<=m;++d){
		head=tail=0;
		for(int i=1;i<=n;++i){
			while(head<tail&&slope(q[head],q[head+1],d)<=2.00*sum[i])++head;
			int j=q[head];
			P[d][i]=(sum[i]-sum[j])*(sum[i]-sum[j])+P[d-1][j];
			while(head<tail&&slope(q[tail-1],q[tail],d)>=slope(q[tail],i,d))--tail;
			q[++tail]=i;
		}
	}
	cout<<m*P[m-1][q[head]]+m*(sum[n]-sum[q[head]])*(sum[n]-sum[q[head]])-sum[n]*sum[n];
	

	
	return 0;
}

by the way

请那位大佬分析一下为什么这样求wa了。。

#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define db double
const int N=3e3+5;

ll P[N][N],ans;
int sum[N],q[N],head,tail,n,m;
/*
	f[d][i]=d*P[d-1][j]+d*(sum[i]-sum[j])^2-sum[i]^2
	2*d*sum[i] * sum[j] + f[d][i] -... =d*(sum[j]^2+P[d-1][j])                  			  
  	 
	2*sum[i]*sum[j]+f[d][i]/d-...=sum[j]^2+P[d-1][j];

  	
	P[d][i]=  (sum[i]-sum[j])^2+ P[d-1][j]
  	2*sum[i] * sum[j] + P[d][i] -... =  P[d-1][j]+sum[j]^2
   
*/
inline db slope(int a,int b,int d){return 1.00*(sum[a]*sum[a]-sum[b]*sum[b]+P[d-1][a]-P[d-1][b])/(1.00*(sum[a]-sum[b]));}
signed main(){
	sf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)sf("%d",&sum[i]),sum[i]+=sum[i-1],P[1][i]=sum[i]*sum[i];
	for(int d=2;d<=m;++d){
		head=tail=0;
	//	pf("d: %d\n",d);
		for(int i=1;i<=n;++i){
		//	pf("i: %d\n",i);
			while(head<tail&&slope(q[head],q[head+1],d)<=2.00*sum[i])++head;
			int j=q[head];
		//	pf("head:%d j:%d \n",head,j);
			P[d][i]=(sum[i]-sum[j])*(sum[i]-sum[j])+P[d-1][j];
			while(head<tail&&slope(q[tail-1],q[tail],d)>=slope(q[tail],i,d))--tail;
			q[++tail]=i;
		//	pf("d :%d i: %d P[d][i]=: %lld\n",d,i,P[d][i]);
		}
	}
	ans=1e10;
	for(int j=m-1;j<n;++j){
		ans=min(ans,(m*P[m-1][j]+m*(sum[n]-sum[j])*(sum[n]-sum[j])-sum[n]*sum[n]));
	}
	cout<<ans;
	

	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值