POJ 3709

简单的单调队列优化,注意是哪些点加入队列即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define N 500050
#define LL __int64
using namespace std;

LL sum[N],dp[N]; int q[N];
int a[N];
int head,tail;

LL getUp(int j,int k){
	return dp[j]-sum[j]+a[j+1]*j-(dp[k]-sum[k]+a[k+1]*k);
}

LL getDown(int j,int k){
	return a[j+1]-a[k+1];
}

int main(){
	int n,T,tmp,k;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&k);
		sum[0]=0;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			sum[i]=sum[i-1]+(LL)a[i];
	//		cout<<sum[i]<<‘ ‘;
			dp[i]=0;
		}
//		cout<<endl;
		head=tail=0;
		int i;
		for(i=1;i<=2*k&&i<=n;i++){
			dp[i]=sum[i]-sum[0]-((LL)a[1])*((LL)i);
	//		cout<<dp[i]<<‘ ‘;
		}
	//	cout<<endl;
		i--;
		if(i==2*k){
			dp[i]=min(dp[i],dp[k]+sum[i]-sum[k]-(LL)a[k+1]*(i-k));
			q[tail++]=k;
			q[tail++]=k+1;
			for(++i;i<=n;i++){
				dp[i]=sum[i]-sum[0]-((LL)a[1])*((LL)i);
			//	cout<<dp[i]<<endl;
				while(head<tail-1&&getUp(q[head+1],q[head])<=((LL)i)*getDown(q[head+1],q[head]))
				head++;
			//	cout<<q[head]<<endl;
				dp[i]=min(dp[i],dp[q[head]]+sum[i]-sum[q[head]]-((LL)a[q[head]+1]*(LL)(i-q[head])));
				while(head<tail-1&&getUp(i-k+1,q[tail-1])*getDown(q[tail-1],q[tail-2])<=getUp(q[tail-1],q[tail-2])*getDown(i-k+1,q[tail-1]))
				tail--;
				q[tail++]=i-k+1;
			}
		}
		printf("%I64d\n",dp[n]);
	}
	return 0;
}

  

时间: 2024-12-17 19:23:56

POJ 3709的相关文章

K-Anonymous Sequence(poj 3709)

http://poj.org/problem?id=3709 给定一个长度为n的非严格单调递增数列a1,...,an.每一次操作可以使数列中的任何一项的值减小1.现在要使数列中的每一项都满足其他项中至少有k-1项和它相等.求最少要对这个数列操作的次数. 输入:第一行为测试数据的组数T(1 ≤ T ≤ 20) 每组测试数据包含两行: 第一行为两个正整数n,k.n为数列中元素的个数 (2 ≤ n ≤ 500000): 第二行为非严格单调递增数列的n个整数,正整数的取值范围为[0, 500000].

poj 3709 K-Anonymous Sequence dp斜率优化

题意: 给长度为n的非严格递增数列a0,a1...an-1,每一次操作可以使数列中的任何一项的值减小1.现在要使数列中每一项都满足其他项中至少有k-1项和它相等.求最少操作次数. 分析: dp[i]:=只考虑前i项情况下,满足要求的最小操作次数. s[i]:=a0+a1+...+ai,则dp[i]=min(dp[j]+s[i]-s[j]-aj*(i-j))(0<=j<=i-k),可以看做dp[i]是这i-k+1条直线在x=i出的最小值,从而进行斜率优化. 代码: //poj 3709 //se

POJ 3709 K-Anonymous Sequence

$dp$,斜率优化. 设$dp[i]$表示前$i$个位置调整成$K-Anonymous$的最小花费. 那么,$dp[i]=min(dp[j]+sum[i]-sum[j]-x[j+1]*(i-j))$. 直接算是$O(n^2)$,进行斜率优化即可. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath&

POJ 3709 K-Anonymous Sequence (斜率优化DP)

题意:有一个不递减的序列,现在要把这些数分成若干个部分,每部分不能少于m个数.每部分的权值为所有数减去该部分最小的数的和.求最小的总权值. 析:状态方程很容易写出来,dp[i] = min{dp[j] + sum[i] - sum[j] - (i-j)*a[j+1] },然而这个复杂度是 O(n^2)的肯定要TLE, 用斜率进行优化,维护一个下凸曲线,注意这个题是有个限制就是至少有要m个是连续的,所以开始的位置是2*m,想想为什么. 代码如下: #pragma comment(linker, "

POJ 3709 K-Anonymous Sequence 斜率优化

容易得出简单的递推方程如下 f[i] = min{f[j] + sum[i] - sum[j] - (i-j) *x[j+1]   } 然后发现复杂度太高 这时可以看出是一个比较经典的斜率优化 f[i] =   min{f[j] +j *x[j+1] -sum[j] -i *x[j+1]}  +sum[i] 按照http://blog.csdn.net/sdj222555/article/details/8229192 中使用的斜率优化方法推导就行了 可以发现一些单调性是比较重要的 最后需要注意

POJ 3709 K-Anonymous Sequence (单调队列优化)

题意:给定一个不下降数列,一个K,将数列分成若干段,每段的数字个数不小于K,每段的代价是这段内每个数字减去这段中最小数字之和.求一种分法使得总代价最小? 思路:F[i]表示到i的最小代价.f[i]=min(f[j]+sum[i]-sum[j]-(i-j)*a[j+1]);(i-j>=K) 对于j1,j2,j1<j2且j2更优得 f[j1]+sum[i]-sum[j1]-(i-j1)*a[j1+1]>f[j2]+sum[i]-sum[j2]-(i-j2)*a[j2+1] 得到: f[j1]

BZOJ 1010 玩具装箱 斜率优化DP

详情见 http://www.cnblogs.com/proverbs/archive/2013/02/01/2713109.html(我觉得这里面讲得已经够详细了,我就不赘述了) 还是来回忆一下做这道题的历程吧!一开始的确有点想错了,但马上又反应过来,清楚了题意.写了个 n^2 的算法.很明显,对于n <=  50000 的数据,肯定是要TLE的.(援引我看博客过程中看到的一句话来形容就是“省选题的数据就是硬”.)没办法,只能上网找百度(太弱了).一开始的确有点茫然,但马上就决定要自己推导一下

数位dp专题 (HDU 4352 3652 3709 4507 CodeForces 55D POJ 3252)

数位dp核心在于状态描述,因为阶段很简单. 一般都是求有多少个数,当然也有求平方的变态题. 因为比这个数小的范围定然是从左至右开始小的,那么什么样的前缀对后面子数有相同的结果? HDU 3652 题意:求能被13整除且含有13这样数的个数. 赤裸裸的两个条件,加上个pre标明下前缀,其实直接开状态也是一样的.整除这个条件可以用余数来表示.余数转移:(mod*10+i)%13 /* *********************************************** Author :bi

(状态压缩DP) poj 2441

Arrange the Bulls Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 3709   Accepted: 1422 Description Farmer Johnson's Bulls love playing basketball very much. But none of them would like to play basketball with the other bulls because the