【数学建模】【APIO2015】Palembang Bridges

Description

一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B。

每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1000000000。相邻的每对建筑相隔 1 个单位距离,河的宽度也是 1 个单位长度。区域 A 中的 i 号建筑物恰好与区域 B 中的 i 号建筑物隔河相对。

城市中有 N 个居民。第 i 个居民的房子在区域 Pi 的 Si 号建筑上,同时他的办公室坐落在 Qi 区域的 Ti 号建筑上。一个居民的房子和办公室可能分布在河的两岸,这样他就必须要搭乘船只才能从家中去往办公室,这种情况让很多人都觉得不方便。为了使居民们可以开车去工作,政府决定建造不超过 K 座横跨河流的大桥。

由于技术上的原因,每一座桥必须刚好连接河的两岸,桥梁必须严格垂直于河流,并且桥与桥之间不能相交。当政府建造最多 K 座桥之后,设 Di 表示第 i 个居民此时开车从家里到办公室的最短距离。请帮助政府建造桥梁,使得 D1+D2+?+DN 最小。

Input

输入的第一行包含两个正整数 K 和 N,分别表示桥的上限数量和居民的数量。

接下来 N 行,每一行包含四个参数:Pi,Si,Qi 和 Ti,表示第 i 个居民的房子在区域 Pi 的 Si 号建筑上,且他的办公室位于 Qi 区域的 Ti 号建筑上。

Output

输出仅为一行,包含一个整数,表示 D1+D2+?+DN 的最小值。

Sample Input

1 5
B 0 A 4
B 1 B 3
A 5 B 7
B 2 A 6
B 1 A 7

Sample Output

24

HINT

K=1或K=2

1≤N≤100000

题解

/*自己搞出来的一道题,真是好感动*/

为了方便,在同一侧的直接处理掉。

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+5;

int abs(int x){return x>0?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*2],l,len,k,n;
ll ans;

void prepare(){
    for(int i=1;i<=l;i++)
        b[++len]=a[i].x,b[++len]=a[i].y;
    sort(b+1,b+len+1);
    for(int i=1;i<=l;i++){
        if(a[i].x>a[i].y) swap(a[i].x,a[i].y);
        a[i].idx=lower_bound(b+1,b+len+1,a[i].x)-b;
        a[i].idy=lower_bound(b+1,b+len+1,a[i].y)-b;
    }
}

int S1[maxn*2],S2[maxn*2];

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=0,cnt=0;
    for(int i=17;i>=0;i--){
        ret+=(1<<i);
        if(ret>len||cnt+C[ret]>=k) ret-=(1<<i);
        else{
            cnt+=C[ret];
        }
    }
    return ret+1;
}

ll solve(){
    ll ans1=0,ans2=0,ansx=0;
    prepare();
    int A=0,B=b[len/2+1];
    for(int i=1;i<=len;i++)
        ans2+=abs(B-b[i]);
    for(int i=1;i<=l;i++)
        add(a[i].idx,1,S2),add(a[i].idy,1,S2);
    ansx=ans2;

    for(int i=1;i<=l;i++){
        int l1=i*2,l2=len-i*2;
        add(a[i].idx,1,S1);add(a[i].idy,1,S1);
        add(a[i].idx,-1,S2);add(a[i].idy,-1,S2);

        ans2-=abs(a[i].x-B)+abs(a[i].y-B);
        A=b[find(l1/2,S1)],B=b[find(l2/2+1,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==1){
        ans=n;
        for(int i=1;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+1,b+l+1);
        int A=b[l/2];
        for(int i=1;i<=l;i++)
            ans+=abs(A-b[i]);
        printf("%lld\n",ans);
    }
    else{
        ans=n;
        for(int i=1;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)-1,l--;
            else a[l].mid=a[l].x+a[l].y;
        }
        sort(a+1,a+l+1);
        printf("%lld",ans+solve());
    }
    return 0;
} 
时间: 2024-08-29 00:36:22

【数学建模】【APIO2015】Palembang Bridges的相关文章

如何入门参加数学建模竞赛

1 网上资源 1.1 数学中国 可以去数学中国网站看看,在数学建模比赛的培训这一块做得很好的机构,如果自己有点银子,可以去参加他们的网上课程.另外他们有专门的数学建模群,群里面有很好关于数学建模的资料.而且这个机构自己也举办数学建模比赛,如果有时候可以在这里组队,直接参加比赛,累积一些经验,增长见识. 1.2 数学建模视频课程,现在网络上有一些比较好的关于数学建模比赛的视频资源,可以谷歌一下 1.3 网络上的一些关于数学建模的电子书,有时候你也不知道哪本书比较适合你,所以你可以先在网上找一些电子

数学建模需掌握的知识总纲

数学建模需要掌握许多知识,这里我列出总纲: 学建模中的算法 穷举法 神经网络 模拟退火 遗传算法 图论算法 蒙特卡洛算法 所需基础知识 高等数学 线性代数(矩阵加减乘除) 概率论与数理统计(概率论,参数估计,假设检验,回归分析) 评价 AHP模型(层次分析) 模糊评价 预测 分析场景 曲线拟合 模糊预测 神经网络 灰色理论 马尔科夫链 运筹 整数规划(分支界定法) 01规划 灵敏度分析 影子价格 概率统计 排队论 主成分分析法 回归分析法 曲线拟合 图论 动态规划 网络最大流 最小费用流 最短路

数学建模基础理论【二】(定积分)

数学建模基础理论[二]                                                                               (定积分) 定义: 定积分分部计算: 平面图形面积: 直坐标情形 极坐标情形 平面曲线的弧长: 平行截面为已知的立体的体积:    

关于数学建模——入门

数学建模的概念:系统的描述某种本质特征的数学表达式 分类:初等/几何/图论/组合/微分方程/线性规划模型/非线性规划模型/目标规划模型/统计回归模型等... 步骤:建立.求解.分析.检验 Notice:数学建模没有唯一正确的答案,评价模型优劣的标准是实践. Model+Algorithm+Program=Map(映射) 数学建模论文的结构: 1.title: 2.summary:3.restatement of the problem(问题引言):4.analysis of the proble

数学建模竞赛“爱你不容易,爱你不后悔”

2011年6月份高中毕业,就读本科,2013年暑假8月份,参加学校为期一个月的数学建模培训,然后9月份的第二个周末在东南大学参加为期三天的全国大学生数学建模竞赛,"意外"获得全国大学生数学建模竞赛二等奖:2015年6月份本科毕业,攻读硕士研究生,2016年暑假,因实习没有参加学校组织的数学建模培训,9月份的第三个周末在南京邮电大学参加为期4.5天的全国研究生数学建模竞赛,"如愿"获得全国研究生数学建模竞赛一等奖,随后在重庆大学参加"华为杯"第十三

数学建模比赛论文的基本结构

一.常用的三种结构 一 二 三 1.摘要 1.摘要 1.摘要 2.问题重述 2.问题的提出与重述.问题的分析 2.问题的叙述.背景的分析 3.问题的分析 3.变量假设 3.模型的假设.符号说明 4.模型假设 4.模型建立 4.模型建立 5.符号说明 5.模型求解 5.模型求解 6.模型建立 6.模型分析与检验 6.模型检验 7.模型求解 7.模型的评价与推广 7.模型评价 8.结果分析.验证.模型检验及修正 8.参考文献 8.参考文献 9.模型评价 9.附录 9.附录 10.参考文献     1

python 版 mldivide matlab 反除(左除)《数学建模算法与程序》Python笔记

今天在阅读数学建模的时候看到了差分那章 其中有一个用matlab求线性的代码,这里我贴出来 这里我送上 Python代码 In [39]: import numpy as np ...: from scipy.optimize import nnls ...: x = np.array([[1,2,3,4,5],[1,1,1,1,1]]) ...: x = x.T ...: y = np.array([11,12,13,15,16]) ...: nnls(x,y) ...: Out[39]: (

【数学建模的五步方法】

第一步,提出问题. ·列出问题中涉及的变量,包括适当的单位. ·注意不要混淆变量的常量. ·列出你对变量所做的全部假设,包括等式和不等式. ·检查单位从而保证你的假设有意义. ·用准确的数学术语给出问题的目标. 第二步,选择建模方法. ·选择结局问的一个一般的求解方法. ·一般地,这一步的成功需要经验.技巧和熟悉相关文献. 第三步,推导模型的数学表达式.·将第一步中得到的问题重新表达成第二步选定额建模方法所需要的形式. ·你可能需要将第一步中的一些变量名改成与第二步所用的记号一致.·记下任何补充

(一)数学建模总论

这是数学模型的第一篇,在数学模型里将整理一些历史上比较有名的数学模型和一些比较重要或者好玩的数学模型,欢迎大家供稿. 数学建模的重要性毋庸置疑. 大概数学建模的过程可以分为以下几个的过程: Step1. 选择一个重要的问题,通常社会科学和自然科学提供了大量的重要的问题.需要有跨学科的思维,当前我们的教育在这方面是不足的. Step2. 对问题的背景熟悉,数学建模也属于应用数学的范畴终归是解决其他学科的问题. Step3. 将问题数学化,一旦数学化就方便进行数学的分析例如选择什么样的数学工具来解决