【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如何 ...
随机推荐
- PAT 1023. 组个最小数 (20)
给定数字0-9各若干个.你可以以任意顺序排列这些数字,但必须全部使用.目标是使得最后得到的数尽可能小(注意0不能做首位).例如:给定两个0,两个1,三个5,一个8,我们得到的最小的数就是1001555 ...
- 学习C++.Primer.Plus 5 循环和关系表达式
C++将赋值表达式的值定义为左侧成员的值 赋值操作符是自右向左结合的 cout.setf(ios:: boolalpha);//调用设置标记,命令cout输出true或false,而非1或0. 任何表 ...
- vbs keys
其使用格式为: object.SendKeys string "object":表示WshShell对象 "string":表示要发送的按键指令字符串,需要放在 ...
- Openwrt iptables分析
这里将载有Openwrt的WR841N的路由表dump出来分析一下. 这个是dump出iptables的命令 root@OpenWrt:/etc/config# iptables-save 这里分为4 ...
- Redis百亿级Key存储方案
1 需求背景 该应用场景为DMP缓存存储需求,DMP需要管理非常多的第三方id数据,其中包括各媒体cookie与自身cookie(以下统称supperid)的mapping关系,还包括了supperi ...
- 【翻译】Windows 10 中为不同设备加载不同页面的3种方法
在以前,为PC和手机做App是两个工程,PC和手机各一个.在Windows 10中会发现只有一个了,对于简单的页面变化可以使用VisualState来解决,但是比如网易云音乐这种PC版和手机版差异巨大 ...
- .Net下一个类型转换神器
引言 类型转换经常遇到,最常用的应该是string类型转换为其它基元类型,常见于http参数类型转换.Convert静态类的Convert.ChangeType()方法可以把实现IConvertibl ...
- sql server死锁神器
参考文章: http://blogs.msdn.com/b/sqlserverfaq/archive/2013/04/27/an-in-depth-look-at-sql-server-memory- ...
- js的Object和Function
自己闲的没事干,自己想通过js的了解写一个Function和Object之间的关系,可以肯定的是我写错了,但是希望可以有所启发. Function和Object Function.__proto__ ...
- 【抄】更改eclipse配置
序言:网上流传着eclipse更改代码提示的一种方法,在eclipse IDE可视化界面没法更改一些东西,比如content assist auto activition trigger在js里面只允 ...