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>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-10;
void File()
{
    freopen("D:\\in.txt","r",stdin);
    freopen("D:\\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c = getchar();
    x = 0;
    while(!isdigit(c)) c = getchar();
    while(isdigit(c))
    {
        x = x * 10 + c - ‘0‘;
        c = getchar();
    }
}

int n,k,T;
long long x[500010],sum[500010],dp[500010];
int f1,f2,q[500010];

bool delete1(int a,int b,int c)
{
    if(dp[b]-sum[b]+b*x[b+1]-c*x[b+1]<=
       dp[a]-sum[a]+a*x[a+1]-c*x[a+1]
       ) return 1;
    return 0;
}

bool delete2(int a,int b,int c)
{
    if(
       ((dp[c]-sum[c]+c*x[c+1])-(dp[b]-sum[b]+b*x[b+1]))*(x[b+1]-x[a+1])<=
       ((dp[b]-sum[b]+b*x[b+1])-(dp[a]-sum[a]+a*x[a+1]))*(x[c+1]-x[b+1])
       ) return 1;
    return 0;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&x[i]);
            sum[i]=sum[i-1]+x[i];
        }

        for(int i=k;i<2*k;i++) dp[i]=sum[i]-i*x[1];

        f1=0; f2=1; q[0]=0; q[1]=k;

        for(int i=2*k;i<=n;i++)
        {
            while(1)
            {
                if(f2-f1+1<2) break;
                if(delete1(q[f1],q[f1+1],i)) f1++;
                else break;
            }

            dp[i]=dp[q[f1]]+sum[i]-sum[q[f1]]-(i-q[f1])*x[q[f1]+1];

            while(1)
            {
                if(f2-f1+1<2) break;
                if(delete2(q[f2-1],q[f2],i-k+1)) f2--;
                else break;
            }

            f2++;
            q[f2]=i-k+1;
        }

        printf("%lld\n",dp[n]);
    }
    return 0;
}
时间: 2024-10-13 03:27:09

POJ 3709 K-Anonymous Sequence的相关文章

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 2081 Recaman&#39;s Sequence

比较简单,加一个B数组判重即可 Recaman's Sequence Time Limit: 3000MS   Memory Limit: 60000K Total Submissions: 21743   Accepted: 9287 Description The Recaman's sequence is defined by a0 = 0 ; for m > 0, am = am−1 − m if the rsulting am is positive and not already i

【POJ】2278 DNA Sequence

各种wa后,各种TLE.注意若AC非法,则ACT等一定非法.而且尽量少MOD. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 using namespace std; 6 7 #define MAXN 105 8 #define NXTN 4 9 10 char str[15]; 11 12 typedef struct Matrix {

poj Problem A. Score Sequence(暴力)

这道题,对于我这种英文不好的人来说,有点费劲啊. 题目的意思:给你两组成绩,你要找出他们之间最大的公共子序列,不能有重复,然后输出两组数据. 第一组就是:按照从大到小输出最大子序列. 第二组就是:按照个位数由小到大输出,若个位数一样大,则小的在前输出最大子序列. 解题思路基本上已经出来了,就是千万要注意就是在最长子序列匹配之前就就把重复的数字给删除. 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h

poj 3017 Cut the Sequence

poj 3017 Cut the Sequence 单调队列 题意是:把一个 长度 为 n 的 数列 分成任意份,使每一份的和不超过m,求每一份的最大值的和,使和最小 动态规划方程 是 f [i] = f[j] + max{ f[j+1] , f[j+2] , f[i] }; 朴素的算法是 O(n^2); 用 单调队列 表示一个递减 的 队列 ,则 不需要 求 每块区域的最大值 哎哎哎……不知道怎么说 #include <iostream> #include <cstdio> #i

poj 2081 Recaman&#39;s Sequence (dp)

Recaman's Sequence Time Limit: 3000MS   Memory Limit: 60000K Total Submissions: 22566   Accepted: 9697 Description The Recaman's sequence is defined by a0 = 0 ; for m > 0, am = am−1 − m if the rsulting am is positive and not already in the sequence,

POJ 2081 Recaman&#39;s Sequence(水题)

[题意简述]:这个题目描述很短,也很简单.不再赘述. [分析]:只需再加一个判别这个数是否出现的数组即可,注意这个数组的范围! // 3388K 0Ms #include<iostream> using namespace std; #define Max 500001 int a[Max]; bool b[10000000] = {false}; // b的数据范围是可以试出来的- void init() { a[0] = 0; b[0] = true; for(int m = 1;m<

【POJ 1019】 Number Sequence

[POJ 1019] Number Sequence 二分水题 放组合数学里...可能有什么正规姿势吧Orz 112123123412345...这种串 分成长度1 2 3 4 5...的串 注意有多位数 把长度累加到一个数组里 注意要累加 因为查询的时候查的是原串中对应位置的数 因此要累加上前一次的长度 然后二分处该串前的总长 用查询的位置-之前串的总长 就是在最长的串中的位置 因此还要打个最长串的表 这些我都写一个循环里了 看着有点乱 可以拆开写... 代码如下: #include <ios

POJ 2448(K短路,A*+SPFA) Remmarguts&#39; Date

题意 给一个n个点m条边的图,然后给一个起点和一个终点,求起点到终点的第K短路. 思路 求第K短路.一个经典的问题. SPFA+A* 核心思想在A*搜索的估计函数的建立上. F(x) = g(x) + h(x) 估价函数 = s到x的距离 + x到t的距离 估价函数的含义就是经过x这个点的路径的距离. 我们在搜索的时候每次选择估价函数较小的值,进行拓展.这样我们搜索到t点的状态出来顺序就是,最短路-次短路-.第三短路- 就减少了我们搜索的状态数. 代码实现上,实现一个估价函数的结构体,然后是实现