【poj3709】 K-Anonymous Sequence
http://poj.org/problem?id=3709 (题目链接)
题意
给出一个n个数的序列,要求将其中一些数改为另一个比它小的数,改动的花费为两数的绝对值,完成改动后使得整个序列中出现过的数出现的次数大于等于K。求最小花费。
Solution
将原序列从大到小排序以后,我们可以发现,每次把连续的一段改成相同的数总是比离散的修改更优。于是我们写出dp方程:${f[i]=Min(f[j]+s[i]-s[j]-a[i]*(i-j))}$。${f[i]}$表示将前${i}$个数修改,并且第${i}$个数保持不变的最小费用;${s[i]}$表示前缀和;${a[i]}$表示第${i}$个数的值。
考虑优化。斜率式:${-a[i]*j+f[i]=(f[j]-s[j])+s[i]-a[i]*i}$。
然而我们发现斜率${-a[i]}$并不是单调的,所以就不能够直接取单调队列队首的元素了,那怎么办呢?只好在队列中二分了,二分的过程很好理解,详情见代码。
以上作废,我在说什么鬼话→_→,${-a[i]}$显然是单调的。。
再附张图,这次的单调队列里面的点构成的图形有点鬼。。竟然是个类似于反比例函数的东西→_→

细节
记得开long long。。。
代码
// poj3709
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1ll<<60
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=500010;
LL a[maxn],f[maxn],s[maxn];
int n,K,q[maxn]; bool cmp(int a,int b) {
return a>b;
}
double slope(int x,int y) {
return (double)((f[y]-s[y])-(f[x]-s[x]))/(double)(y-x);
}
int main() {
int T;scanf("%d",&T);
while (T--) {
scanf("%d%d",&n,&K);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
for (int i=1;i<=n;i++) f[i]=inf;
int l=1,r=1;q[1]=0;
for (int i=K;i<=n;i++) {
while (l<r && slope(q[l],q[l+1])<-a[i]) l++;
f[i]=f[q[l]]+s[i]-s[q[l]]-a[i]*(i-q[l]);
while (l<r && slope(q[r-1],q[r])>slope(q[r],i-K+1)) r--;
q[++r]=i-K+1;
}
printf("%lld\n",f[n]);
}
return 0;
}
代码(强行二分)
// poj3709
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1e18
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std; const int maxn=500010;
LL f[maxn],s[maxn],a[maxn];
int q[maxn],n,K; double slope(int x,int y) {
return (double)((f[y]-s[y])-(f[x]-s[x]))/(double)(y-x);
}
int find(int l,int r,LL x) {
int res=l;
while (l<=r) {
int mid=(l+r)>>1;
if (mid<r && x>slope(q[mid],q[mid+1])) l=mid+1,res=mid;
else if (mid>l && x<slope(q[mid-1],q[mid])) r=mid-1,res=mid;
else return mid;
}
return res;
}
bool cmp(LL a,LL b) {
return a>b;
}
int main() {
int T;scanf("%d",&T);
while (T--) {
scanf("%d%d",&n,&K);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
for (int i=1;i<=n;i++) f[i]=inf;
int l=1,r=1;q[1]=0;
for (int i=K;i<=n;i++) {
int x=find(l,r,-a[i]);
f[i]=f[q[x]]+s[i]-s[q[x]]-a[i]*(i-q[x]);
while (l<r && slope(q[r-1],q[r])>slope(q[r],i-K+1)) r--;
q[++r]=i-K+1;
}
printf("%lld\n",f[n]);
}
return 0;
}
【poj3709】 K-Anonymous Sequence的更多相关文章
- 【CF486E】LIS of Sequence题解
[CF486E]LIS of Sequence题解 题目链接 题意: 给你一个长度为n的序列a1,a2,...,an,你需要把这n个元素分成三类:1,2,3: 1:所有的最长上升子序列都不包含这个元素 ...
- 【BZOJ3110】K大数查询(整体二分)
[BZOJ3110]K大数查询(整体二分) 题面 BZOJ 题解 看了很久整体二分 一直不知道哪里写错了 ... 又把树状数组当成线段树区间加法来用了.. 整体二分还是要想清楚在干什么: 我们考虑第\ ...
- 【CF1133E】K Balanced Teams(动态规划,单调队列)
[CF1133E]K Balanced Teams(动态规划,单调队列) 题面 CF 让你把一堆数选一些出来分成不超过\(K\)组,每一组里面的最大值和最小值之差不超过\(5\),求最多有多少个人元素 ...
- 【BZOJ4355】Play with sequence 线段树
[BZOJ4355]Play with sequence Description 维护一个长度为N的序列a,现在有三种操作: 1)给出参数U,V,C,将a[U],a[U+1],...,a[V-1],a ...
- 【BZOJ4520】K远点对(KD-Tree)
[BZOJ4520]K远点对(KD-Tree) 题面 BZOJ 洛谷 题解 考虑暴力. 维护一个大小为\(K\)的小根堆,然后每次把两个点之间的距离插进去,然后弹出堆顶 这样子可以用\(KD-Tree ...
- 【BZOJ4504】K个串 可持久化线段树+堆
[BZOJ4504]K个串 Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...
- 【题解】Cut the Sequence(贪心区间覆盖)
[题解]Cut the Sequence(贪心区间覆盖) POJ - 3017 题意: 给定一大堆线段,问用这些线段覆盖一个连续区间1-x的最小使用线段的数量. 题解 考虑一个这样的贪心: 先按照左端 ...
- 【规律】A Rational Sequence
题目描述 An infinite full binary tree labeled by positive rational numbers is defi ned by:• The label of ...
- 【动态规划】XMU 1583 Sequence
题目链接: http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1583 题目大意: T组数据,对于n(n<=6000)给定序列Xn(Xn<= ...
- 【SPOJ】2319 BIGSEQ - Sequence
[算法]数位DP [题解]动态规划 题目要求的是大整数……没办法只写了小数字的,感觉应该没错. 大题框架是最大值最小化的二分问题. 对于每一块要求count(b)-count(a-1)≥s 已知a如何 ...
随机推荐
- css position, display, float 内联元素、块级元素
position属性:position属性指出一个元素的定位方法.有4种可能值:static, relative, absolute or fixed: static:默认值,元素按照在文档流中出现的 ...
- 代码整洁--使用CodeMaid自动程序排版
在项目开发的过程中,如果只是验证命名规则.而没有统一程序排版,项目中很容易就会出现类似下列范例的程序代码产出.这样的产出,虽然能够正常地提供项目功能.并且符合微软的命名规则,但是因为程序排版凌乱的问题 ...
- Map集合 总结
(本人第一次写博客,部分内容有参照李刚老师的疯狂java系列图书,如有遗漏错误,请多指教,谢谢.) Java的集合类可分为Set.List.Map.Queue,其中Set.List.Queue都有共同 ...
- 2015-2016-2 《Java程序设计》 游戏化
2015-2016-2 <Java程序设计> 游戏化 实践「<程序设计教学法--以Java程序设计为例>」中的「游戏化(Gamification)理论」,根据 2015-201 ...
- "本地泛解析"或者叫做”域名劫持泛解析“,做开发二级域名在内网测试
都不知道怎么称呼这个好,暂且叫 “本地泛解析” 吧 . 大概就是,要做一个二级域对应一个用户的这种功能,类似博客园,我的博客地址是:jerseyblog.cnblogs.com ,你的博客就可能是 x ...
- JavaScript高级程序设计笔记 事件冒泡和事件捕获
1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> & ...
- git的理解
1.对git的分支怎么理解. git的本地,git的跟踪,如果我们的本地的命令行进入某个分支的话,我们的本地对应的文件夹就显示某个,然后我们的ide打开的就是那个分支 2.git的在线视频教学 htt ...
- The Lifecycle and Cascade of WeChat Social Messaging Groups-www2016-20160512
分析性论文: 分析并预测微信群的生命周期,以及群成员的邀请模式. 参考资料:http://www.360doc.com/content/16/0423/11/26166517_553076725.sh ...
- 用Intent实现activity的跳转
新建一个FirstAvtivity.java package com.zhuguangwei; import android.app.Activity;import android.content.I ...
- 0930MySQL中实现高性能高并发计数器方案(例如文章点击数)
转自http://www.jb51.net/article/56656.htm 这篇文章主要介绍了MySQL中实现高性能高并发计数器方案,本文中的计数器是指如文章的点击数.喜欢数.浏览次数等,需要的朋 ...