[HackerRank]Hard Disk Drives/[JZOJ100005]Shoes
来源:互联网 发布:人体数据 编辑:程序博客网 时间:2024/06/05 14:24
题目大意
一个数轴上有
你需要在数轴上任意位置选择
请你选择这
题目分析
将每一对点看成数轴上的一个区间,分析发现,不管怎么移动点,两个点在移动过程中,要么一个点跨过该区间,要么两个点在区间内汇合,总之一对点的移动距离和至少是区间长度,至于出来的部分,如果区间内有关键点,那么就没有额外的消耗,否则一定是区间其中的一个端点与其距离最近的关键点的距离的两倍。
我们撇开区间本身造成的贡献(最后再加上去),考虑如何求上面所说的“多出来的部分”,为了方便计算我们先不将上面那个距离乘二,最后再乘上去。
于是现在我们的问题是,有若干个数轴上的区间,你要加入
可以发现,一定存在一种最优解使得关键点都取值在数轴上原有的点。
考虑dp,令
令
dp方程如下:
这样做是
可以发现,令
那么使用经典的决策单调性分治套路,每次计算出中点的取值点,然后分治两边,即可做到
注意使用各种离散化来卡常。
代码实现
#include <algorithm>#include <iostream>#include <climits>#include <cstdio>#include <cctype>using namespace std;typedef long long LL;int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar(); while (isdigit(ch)) x=x*10+ch-'0',ch=getchar(); return x*f;}const LL INF=LLONG_MAX/2;const int N=100050;const int X=N<<1;const int LGN=17;const int S=N*LGN;struct chairman_tree{ int son[S][2],size[S]; LL sum[S]; int tot; int newnode(int rt) { sum[++tot]=sum[rt],size[tot]=size[rt]; son[tot][0]=son[rt][0],son[tot][1]=son[rt][1]; return tot; } void init(){tot=0;} void modify(int &rt,int rt0,int x,int l,int r,int delta) { rt=newnode(rt0); ++size[rt],sum[rt]+=delta; if (l==r) return; int mid=l+r>>1; if (x<=mid) modify(son[rt][0],son[rt0][0],x,l,mid,delta); else modify(son[rt][1],son[rt0][1],x,mid+1,r,delta); } void query(int rt,int rt0,int x,int l,int r,int &CNT,LL &SUM) { if (!x) return; if (!(size[rt]-size[rt0])) return; if (l==r) { if (x==l) CNT+=size[rt]-size[rt0],SUM+=sum[rt]-sum[rt0]; return; } int mid=l+r>>1; if (x<=mid) query(son[rt][0],son[rt0][0],x,l,mid,CNT,SUM); else CNT+=size[son[rt][0]]-size[son[rt0][0]],SUM+=sum[son[rt][0]]-sum[son[rt0][0]],query(son[rt][1],son[rt0][1],x,mid+1,r,CNT,SUM); }}t[2];int a[N],b[N],newa[N],newb[N],news[N],xval[N],sval[N];int root[X][2];LL f[X],g[X];int n,K,xtot,stot,xcnt,scnt;LL ans;struct data{ int key,id; bool tp; bool operator<(data const x)const{return key<x.key;}}srt[X];void pre(){ for (int i=1;i<=n;++i) srt[++stot].key=a[i]+b[i],srt[stot].id=i; sort(srt+1,srt+1+stot),srt[0].key=-2000000001,scnt=0; for (int i=1;i<=stot;++i) sval[news[srt[i].id]=scnt+=srt[i].key!=srt[i-1].key]=srt[i].key; for (int i=1;i<=n;++i) { srt[++xtot].key=a[i],srt[xtot].id=i,srt[xtot].tp=0; srt[++xtot].key=b[i],srt[xtot].id=i,srt[xtot].tp=1; } sort(srt+1,srt+1+xtot),srt[0].key=-1000000001,xcnt=0,xval[0]=-2000000001; t[0].init(),t[1].init(); int lstl=0,lstr=0,lrtl=0,lrtr=0; for (int i=1;i<=xtot;++i) { xval[xcnt+=srt[i].key!=srt[i-1].key]=srt[i].key; if (srt[i].tp) { newb[srt[i].id]=xcnt; for (int j=lstr+1;j<xcnt;++j) root[j][1]=root[j-1][1]; t[1].modify(root[xcnt][1],lrtr,news[srt[i].id],1,scnt,b[srt[i].id]); lstr=xcnt,lrtr=root[xcnt][1]; } else { newa[srt[i].id]=xcnt; for (int j=lstl+1;j<xcnt;++j) root[j][0]=root[j-1][0]; t[0].modify(root[xcnt][0],lrtl,news[srt[i].id],1,scnt,a[srt[i].id]); lstl=xcnt,lrtl=root[xcnt][0]; } } for (int i=lstl+1;i<=xcnt;++i) root[i][0]=root[i-1][0]; for (int i=lstr+1;i<=xcnt;++i) root[i][1]=root[i-1][1];}int search(int x){ int ret=0,l=1,r=scnt; for (int mid;l<=r;) { mid=l+r>>1; if (sval[mid]<=x) l=(ret=mid)+1; else r=mid-1; } return ret;}void dp(int l,int r,int st,int en){ if (l>r) return; int mid=l+r>>1,p; for (int i=st;i<=en&&i<=mid;++i) { int CNT;LL SUM,tmp=0; CNT=0,SUM=0,t[0].query(root[mid][0],i?root[i-1][0]:0,search(!i?INT_MIN:xval[i]+xval[mid]),1,scnt,CNT,SUM); tmp+=SUM-1ll*CNT*xval[i]; CNT=0,SUM=0,t[1].query(root[mid][1],i?root[i-1][1]:0,search(!i?INT_MIN:xval[i]+xval[mid]),1,scnt,CNT,SUM); CNT=t[1].size[root[mid][1]]-t[1].size[i?root[i-1][1]:0]-CNT,SUM=t[1].sum[root[mid][1]]-t[1].sum[i?root[i-1][1]:0]-SUM; tmp+=1ll*CNT*xval[mid]-SUM+g[i]; if (f[mid]>tmp) f[mid]=tmp,p=i; } dp(l,mid-1,st,p),dp(mid+1,r,p,en);}void calc(){ ans=INF; for (int i=1;i<=xcnt;++i) f[i]=INF; g[0]=0; for (int k=1;k<=K;++k) { for (int i=1;i<=xcnt;++i) g[i]=f[i],f[i]=INF; dp(1,xcnt,0,xcnt); int CNT=0;LL SUM=0; for (int i=xcnt,cur=xtot;i>=1;--i) { for (;cur&&srt[cur].key>=xval[i];--cur) if (!srt[cur].tp) ++CNT,SUM+=a[srt[cur].id]; ans=min(ans,f[i]+SUM-1ll*CNT*xval[i]); } } ans*=2;}int main(){ freopen("shoes.in","r",stdin),freopen("shoes.out","w",stdout); n=read(),K=read(); for (int i=1;i<=n;++i) { a[i]=read(),b[i]=read(); if (a[i]>b[i]) swap(a[i],b[i]); } pre(),calc(); for (int i=1;i<=n;++i) ans+=b[i]-a[i]; printf("%lld\n",ans); fclose(stdin),fclose(stdout); return 0;}
0 0
- [HackerRank]Hard Disk Drives/[JZOJ100005]Shoes
- 【JZOJ100005】【NOI2017模拟.4.1】Shoes
- 【JZOJ100005】【NOI2017模拟.4.1】Shoes
- How to Configure Hard Disk Drives on a CEPC
- Hackerrank Hard Homework
- ivman does not mount usb hard drives
- about ubuntu hard disk
- hard disk boot priority
- Hard disk hacking - Intro
- HDU4788 Hard Disk Drive
- Hard Disk Speed - What Affects Hard Disk Performance?
- Reformat and_recover hard disk procedure
- Clone Hard Disk Under Linux
- Linux Hard Disk Format Command
- Linux Hard Disk Format Command
- Linux Hard Disk Format Command
- Linux Hard Disk Format Command
- hdu 4788 Hard Disk Drive
- objcopy的详细说明
- php 静态方式调用非静态的方法
- 360笔试题-主任务和临时任务的分配
- eclipse快捷键
- init 启动 Native Service 时出现Service xxxx needs a SELinux domain defined; please fix 警告的说明
- [HackerRank]Hard Disk Drives/[JZOJ100005]Shoes
- PHP内核探索之变量(3)- hash table
- Java API的中度使用
- Nginx如何处理一个请求
- U3D常用方法
- C# 绘制统计图(柱状图, 折线图, 扇形图)
- 学习的文章
- AJAX
- 使用MySQL命令行新建用户并授予权限的方法