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]-sum[j1]+a[j1+1]*j1)-(f[j2]-sum[j2]+a[j2+1]*j2)>=i*(a[j1+1]-a[j2+1])

可以用单调队列维护.

由于每一层需要K个,所以我们延迟入队的时间.

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #define ll long long
 7 long long f[1000005],sum[1000005],a[1000005];
 8 int c[1000005];
 9 int n,K,T;
10 ll G(int j,int k){
11     return f[j]-sum[j]+j*a[j+1]-(f[k]-sum[k]+k*a[k+1]);
12 }
13 ll S(int j,int k){
14     return a[j+1]-a[k+1];
15 }
16 int main(){
17     scanf("%d",&T);
18     while (T--){
19         scanf("%d%d",&n,&K);
20         sum[0]=0;
21         for (int i=1;i<=n;i++) scanf("%I64d",&a[i]);
22         for (int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i],f[i]=0;
23         int h=0,t=0;
24         c[t++]=0;f[0]=0;
25         for (int i=1;i<=n;i++){
26             while (h<t-1&&G(c[h],c[h+1])>=i*S(c[h],c[h+1])) h++;
27             f[i]=(ll)f[c[h]]+sum[i]-sum[c[h]]-(i-c[h])*a[c[h]+1];
28             if (i>=2*K-1) c[t++]=i-K+1;
29             for (int j=t-2;j>h;j--){
30              int x=c[j-1],y=c[j],z=c[j+1];
31              if (G(x,y)*S(y,z)>=G(y,z)*S(x,y)) c[j]=c[--t];
32              else break;
33             }
34         }
35         printf("%I64d\n",f[n]);
36     }
37 }
时间: 2024-10-30 23:58:23

POJ 3709 K-Anonymous Sequence (单调队列优化)的相关文章

POJ 1742 Coins 多重背包单调队列优化

http://poj.org/problem?id=1742 题意: 很多硬币,有价值和数量,给出一个上限,问上限内有多少种钱数可以由这些硬币组成. 分析: 好像是楼教主男人八题之一.然后学多重背包单调队列优化时看了别人的程序..所以后来写了就1A了=.= 前一篇小小总结了一下多重背包单调队列优化(http://www.cnblogs.com/james47/p/3894772.html),这里就不写了. 1 #include<cstdio> 2 #include<cstring>

$Poj3017\ Cut\ The\ Sequence$ 单调队列优化$DP$

Poj   AcWing Description 给定一个长度为N的序列 A,要求把该序列分成若干段,在满足“每段中所有数的和”不超过M的前提下,让“每段中所有数的最大值”之和最小. N<=105,M<=1011,0<Ai<=106 Sol 一篇比较清楚的题解 $OvO$ $F[i]$表示把前$i$个数分成若干段,满足每段中所有数之和不超过$M$的前提下,各段的最大值之和的最小值 不难推出转移方程: 但是直接枚举$j$的做法是$O(N^{2})$的,显然过不去,还要优化. DP转移

Parade(单调队列优化dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 902    Accepted Submission(s): 396 Problem Description Panagola, The Lord of city F lik

poj 3017 Cut the Sequence(单调队列优化 )

题目链接:http://poj.org/problem?id=3017 题意:给你一个长度为n的数列,要求把这个数列划分为任意块,每块的元素和小于m,使得所有块的最大值的和最小 分析:这题很快就能想到一个DP方程 f[ i ]=min{ f[ j ] +max{ a[ k ] }}( b[ i ]<j<i,j<k<=i)     b[ i ]到 i的和大于m 这个方程的复杂度是O(n^2),明显要超时的(怎么discuss都说数据弱呢= =) 然后是优化了,首先当然是要优化一个最大

POJ 3017 Cut the Sequence (单调队列优化DP)

POJ 3017 Cut the Sequence (单调队列优化DP) ACM 题目地址: POJ 3017 Cut the Sequence 题意: 将一个由N个数组成的序列划分成若干段,要求每段数字的和不超过M,求[每段的最大值]的和 的最小的划分方法,输出这个最小的和. 分析: 方程是:dp[i] = min(dp[j]+maxsum[j+1][i]) 但复杂度n*n太高,需要优化. 可以用单调队列+BST优化,其实只需要维护每一段的最大值. 看了这篇题解的:http://blog.cs

每日一dp(1)——Largest Rectangle in a Histogram(poj 2559)使用单调队列优化

Largest Rectangle in a Histogram 题目大意: 有数个宽为1,长不定的连续方格,求构成的矩形中最大面积 /************************************************************************/ /* 思路1. 当前为n的面积如何与n-1相联系,dp[i][j]=max(dp[i-1][k]) , 0<k<=j 描述:i为方块个数,j为高度 但是此题目的数据对于高度太变态,h,1000000000 ,n,1

POJ 3926 Parade 单调队列优化DP

来源:http://poj.org/problem?id=3926 题意:行n <= 100, 列m <= 10000,类似于数字三角形,一个人要从底下往上走,每层中可以左右走,但选定方向不能回头(向左不能再向右),每经过一段获得该段的一个值,并走了该段的距离,在同一层走的距离不能超过k.问走到最顶头,获得的总值最大是多少. 分析:dp[i][j]表示走到第i行第j列,获得的值最大为多少.则dp[i][j] = max(dp[i+1][p] + sum(p to j)),sum(p to j)

POJ 1821 Fence(单调队列优化DP)

题解 以前做过很多单调队列优化DP的题. 这个题有一点不同是对于有的状态可以转移,有的状态不能转移. 然后一堆边界和注意点.导致写起来就很难受. 然后状态也比较难定义. dp[i][j]代表前i个人涂完前j个位置的最大收益. 然后转移考虑 第i个人可以不刷.dp[i][j]=dp[i-1][j]; 第j个木板可以不刷dp[i][j]=dp[i][j-1]; 然后当c[i].s<=j<=s[i]+l[i]-1时 dp[i][j]=p[i]*j+max(dp[i-1][k]-p[i]*k)其中j-

【POJ】2373 Dividing the Path(单调队列优化dp)

题目 传送门:QWQ 分析 听说是水题,但还是没想出来. $ dp[i] $为$ [1,i] $的需要的喷头数量. 那么$ dp[i]=min(dp[j])+1 $其中$ j<i $ 这是个$ O(n^2)$的东西,用单调队列优化一下就行了 复杂度$ O(L) $ 代码 #include <bits/stdc++.h> using namespace std; const int maxn=250; int A[maxn][maxn], num[maxn*maxn], id[100000