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

 

【题目链接】 http://poj.org/problem?id=3709

 

【题目大意】

  给出一个长度为n个非严格单调递增数列,每次操作可以使得其中任意一项减一,
  问现在使得数列中每项数相同的数的数量都大于等于k-1,问最少进行几次操作

 

【题解】

  我们设dp[i]为前i项答案,得到方程dp[i]=min(dp[j]+S[i]-S[j]-aj*(i-j)),
  dp[i]=S[i]+min(dp[j]-S[j]+aj*j-aj*i),为关于i的线性函数,
  所以我们对f(y)=-ax*y+dp[x]-S[x]+ax*x进行斜率优化。

 

【代码】

#include <algorithm>
#include <cstdio>
#include <cstring>
typedef long long LL;
const int MAX_N=500010;
int n,k;
LL a[MAX_N],dp[MAX_N],S[MAX_N],deq[MAX_N];
LL f(int x,int y){return -a[x]*y+dp[x]-S[x]+a[x]*x;}
bool check(int f1,int f2,int f3){
    LL a1=-a[f1],b1=dp[f1]-S[f1]+a[f1]*f1;
    LL a2=-a[f2],b2=dp[f2]-S[f2]+a[f2]*f2;
    LL a3=-a[f3],b3=dp[f3]-S[f3]+a[f3]*f3;
    return (a2-a1)*(b3-b2)>=(b2-b1)*(a3-a2);
}
void solve(){
    for(int i=0;i<n;i++)S[i+1]=S[i]+a[i];
    int s=0,t=1;
    deq[0]=0; dp[0]=0;
    for(int i=k;i<=n;i++){
        if(i-k>=k){
            while(s+1<t&&check(deq[t-2],deq[t-1],i-k))t--;
            deq[t++]=i-k;
        }while(s+1<t&&f(deq[s],i)>=f(deq[s+1],i))s++;
        dp[i]=S[i]+f(deq[s],i);
    }printf("%lld\n",dp[n]);
}int T;
int main(){
	scanf("%d",&T); 
    while(T--){
        scanf("%d%d",&n,&k);
		for(int i=0;i<n;i++)scanf("%lld",&a[i]);
        solve();
    }return 0;
}
posted @ 2017-04-11 16:50  forever97  阅读(173)  评论(0编辑  收藏  举报