• 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
    ",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;
    }
  • 相关阅读:
    6410实现网卡(DM9000A)收发功能及ARP协议实现
    Shuffling Machine和双向链表
    Have Fun with Numbers及循环链表(约瑟夫问题)
    Tiny6410 LCD设置
    RAM与内存
    inet_addr解析
    map容器find用法
    WinSock编程(TCP)
    Python 时间序列作图及注释
    无法打开之前cuda的vs项目,打开之后变灰色
  • 原文地址:https://www.cnblogs.com/forever97/p/poj3709.html
Copyright © 2020-2023  润新知