[HDU][3045][Picnic Cows][斜率优化]

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;

#define min(a,b) ( (a)< (b)? (a): (b) )
int n, m;
int const N= 400100;
typedef long long LL;

/*
dp[i]= min{ dp[j]+ sum[i]- sum[j]+ ( i- j )* data[j+ 1] }
要求分段的序列长度不小于 m,即 i- j+ 1>= m
 
假设 j> k, 要使决策 j 比决策 k 优, 则有
dp[j]+ sum[i]- sum[j]+ ( i- j )* data[j+ 1]<
dp[k]+ sum[i]- sum[k]+ ( i- k )* data[k+ 1]
整理有:
dp[j]- sum[j]- j* data[j+ 1]- ( dp[k]- sum[k]- k* data[k+ 1] )
< i* ( data[j+ 1]- data[k+ 1] )

所以 j 比 k 优等价于 
( dp[j]- dp[k]- sum[j]+ sum[k]- j* data[j+ 1]+ k* data[k+ 1] )/
( data[j+ 1]- data[k+ 1] )< i

今 F[j,k]= 上式左边
对于 k< j< i< t
假设 F[j, k]> F[i, j]
如果 F[i, j]< t 则 i 比 j 优
如果 F[i, j]> t 则 F[j, k]> t 得到 k 比 j 优
故对于满足条件 F[j,k]> F[i,j] 的可以剔除 j 状态

因为长度要不小于 2* m 故 1到 m- 1 都不可能成为决策点
对于 i, 能成为 i 状态的决策点的最小 j 为 i- m+ 1,并且对于
t> i, 这个最小 j= i- m+ 1 也有可能成为 t 的决策点 
故对于当前状态 i ( i- m+ 1>= m ) 将决策点 i- m+ 1 加入 
*/

LL dp[N], data[N], sum[N];
int que[N], head, tail;

inline LL S( int j, int k ){
	return data[j+ 1]- data[k+ 1];
}

inline LL G( int j, int k ){
	return  dp[j]- sum[j]+ j* data[j+ 1]-
	      ( dp[k]- sum[k]+ k* data[k+ 1] );
}

int main(){
	while( scanf("%d%d",&n,&m)!= EOF ){
		sum[0]= 0;
		for( int i= 1; i<= n; ++i )scanf("%I64d", data+ i );
		
		sort( data+ 1, data+ 1+ n );
		for( int i= 1; i<= n; ++i )sum[i]= sum[i-1]+ data[i];
		
		head= 0, tail= 0;
		que[++tail]= 0; dp[0]= 0;

		for( int i= m; i<= n; ++i ){
			while( head< tail  && S(que[head+ 1],que[head])* i>= G( que[head+ 1], que[head] ) )
			head++; 
			
			dp[i]= dp[ que[head] ]+ ( sum[i]-sum[que[head]] )- ( i- que[head] )* data[ que[head]+ 1 ];
			
			if( i- m+ 1>= m ) que[++tail]= i- m+ 1;
			int j= que[tail]; tail--;
			
			while( head< tail && G( que[tail], que[tail-1] )* S( j, que[tail] )>=
			                     G( j, que[tail] )* S( que[tail], que[tail-1] ) ) tail--;
			                     
		    que[++tail]= j;
		}
		
		printf("%I64d\n", dp[n] );
	}
	
	return 0;
}

 

你可能感兴趣的:(F#,J#)