【数学建模】【APIO2015】Palembang Bridges
Description
一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B。
Input
输入的第一行包含两个正整数 K 和 N,分别表示桥的上限数量和居民的数量。
Output
输出仅为一行,包含一个整数,表示 D1+D2+⋯+DN 的最小值。
Sample Input
B 0 A 4
B 1 B 3
A 5 B 7
B 2 A 6
B 1 A 7
Sample Output
HINT
K=1或K=2
题解
/*自己搞出来的一道题,真是好感动*/
为了方便,在同一侧的直接处理掉。
K=1时,显然就是取中位数。
K=2时,考虑每一对(S,T),(绿蓝代表两座桥),那么肯定是要选两条红线短的那一边。不过这样还不够好考虑,我们不如让着两条直线伸长相等的距离,延伸到中点。
于是对于每一对(S,T),直接看Mid到两墙的距离就可以选择了。
进一步得出,如果我们把它们按中点排序,那么最后的局面肯定是,左部分都去桥1,右部分都去桥2,有一个分割点。
那么我们可以枚举分割点,分别计算两部分的最优桥,很神奇的把K=2分成了两个K=1,得到n^2的算法。
显然最优桥我们是可以动态维护的。
考虑点i(一对ST),把它从右部分加入左部分。
那么它对于最优桥的影响是可以讨论的,过程很傻逼可以自己试一试。
我得到的结果是,考虑左右部分肯定都是偶数,那么另左部分中位数取(len/2),右部分中位数取(len/2+1),这么做比较方便。
然后加点到左部分的时候,因为我们已经按中点排序,所以只可能是一左一右或者两右(左右是相对当前最优桥而言的)。
那么如果是一左一右,最优桥不发生变化,对ans新的贡献也就是这个点的贡献。
如果是两右,会使最优桥右移一位,但对于之前已加入的点是没有影响的,ans的改变还是只有这个点。
于是用两个树状数组模拟两边,每次求最优桥(这个也用树状数组求第k小数),然后维护ans也就是计算当前点的影响就行了。
复杂度O(nlogn)。说不清还是看代码吧。
主要考察数学建模、对数据结构的应用,感觉这题还是蛮好的。
代码
代码能力各种逗啊QwQ 调了好久 但调出来后真是好久没觉得这么爽了
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1e5+; int abs(int x){return x>?x:-x;} struct point{
int x,y,idx,idy,mid;
bool operator <(const point&aa)
const {return mid<aa.mid;}
}a[maxn]; int b[maxn*],l,len,k,n;
ll ans; void prepare(){
for(int i=;i<=l;i++)
b[++len]=a[i].x,b[++len]=a[i].y;
sort(b+,b+len+);
for(int i=;i<=l;i++){
if(a[i].x>a[i].y) swap(a[i].x,a[i].y);
a[i].idx=lower_bound(b+,b+len+,a[i].x)-b;
a[i].idy=lower_bound(b+,b+len+,a[i].y)-b;
}
} int S1[maxn*],S2[maxn*]; int lowbit(int o){return o&-o;}
int add(int o,int k,int* C){
while(o<=len){
C[o]+=k;
o+=lowbit(o);
}
} int find(int k,int *C){
int ret=,cnt=;
for(int i=;i>=;i--){
ret+=(<<i);
if(ret>len||cnt+C[ret]>=k) ret-=(<<i);
else{
cnt+=C[ret];
}
}
return ret+;
} ll solve(){
ll ans1=,ans2=,ansx=;
prepare();
int A=,B=b[len/+];
for(int i=;i<=len;i++)
ans2+=abs(B-b[i]);
for(int i=;i<=l;i++)
add(a[i].idx,,S2),add(a[i].idy,,S2);
ansx=ans2; for(int i=;i<=l;i++){
int l1=i*,l2=len-i*;
add(a[i].idx,,S1);add(a[i].idy,,S1);
add(a[i].idx,-,S2);add(a[i].idy,-,S2); ans2-=abs(a[i].x-B)+abs(a[i].y-B);
A=b[find(l1/,S1)],B=b[find(l2/+,S2)];
ans1+=abs(a[i].x-A)+abs(a[i].y-A);
if(ans1+ans2<ansx) ansx=ans1+ans2;
}
return ansx;
} int main(){
char p,q;
int u,v;
scanf("%d%d",&k,&n);
if(k==){
ans=n;
for(int i=;i<=n;i++){
scanf("\n%c %d %c %d",&p,&u,&q,&v);
if(p==q) ans+=abs(u-v),ans--;
else b[++l]=u,b[++l]=v;
}
sort(b+,b+l+);
int A=b[l/];
for(int i=;i<=l;i++)
ans+=abs(A-b[i]);
printf("%lld\n",ans);
}
else{
ans=n;
for(int i=;i<=n;i++){
l++;
scanf("\n%c %d %c %d",&p,&a[l].x,&q,&a[l].y);
if(p==q) ans+=abs(a[l].x-a[l].y)-,l--;
else a[l].mid=a[l].x+a[l].y;
}
sort(a+,a+l+);
printf("%lld",ans+solve());
}
return ;
}
最新文章
- Android接入百度自动更新SDK
- View与Control间的数据交互
- sass入门
- eclipse SE增加Web开发插件;安装配置Apache
- 创建mysql存储过程,调用 及删除
- 攻城狮在路上(壹) Hibernate(十)--- 映射值类型集合
- 外观模式/facade模式/结构型模式
- Android内存泄漏监测(MAT)及解决办法
- Maven配置插件跳过测试代码的编译和运行
- 视频云SDK iOS持续集成项目实践
- 《Linux就该这么学》 - 必读的红帽系统与红帽linux认证自学手册
- j2ee第五周
- ElasticSearch(五):Java操作ElasticSearch执行查询
- 冲刺Two之站立会议9
- 事件对象——event
- UDP template 代码
- IOS6 IOS7 Mapkit draw Rout(地图划线)
- jQuery使用scrollTop获取div标签的滚动条已滚动高度(jQuery版本1.6+时,用prop()方法代替attr()方法)
- Android与GPL、BSD和Apache之间的关系
- jquery中filter(fn)的使用研究
热门文章
- 关于iOS9 HTTP不能正常使用的解决方法
- 记一次erlang语言bug导致rabbitmq的队列没有消费者的问题
- Spring的事务 之 9.4 声明式事务 ——跟我学spring3
- 修改访问的后缀contant
- 几个大型网站的Feeds(Timeline)设计简单对比
- wxpython实现界面跳转
- 从 <;sofa:XXX>; 标签开始看 SOFA-Boot 如何融入 Spring
- 基于DP的LCS(最长公共子序列)问题
- linux下svn(subversion)服务端添加工程及配置权限
- 原生js实现canvas气泡冒泡效果