[CQOI2012] 组装 - 贪心

数轴上有 \(n\) 种点,总共有 \(m\) 个,每个点有它的坐标 \(x_i\) 和种类 \(p_i\)。求一个点,使得所有种类点中与这个点的最小距离的平方和最小。\(n \le 10^4, m \le 10^5, x_i \le 10^5\)

Solution

要最小化 \(\sum_{i=1}^n (x-x_i)^2\),显然在选定了每个种类使用的点以后,这是一个关于 \(x\) 的二次函数,其最小值为

\[\sum_{i=1}^n x_i^2 - \frac 1 n \sum_{i=1}^n x_i
\]

于是现在我们只需要考虑如何选择每个种类使用的点

对于同一种点按坐标从小到大排序,每次枚举把某种点替换成他的下一个

由于原式取得最小值的条件是 \(x= \frac 1 n \sum_{i=1}^n x_i\)

我们将每次替换用一个二元组 \((x_i,x_i‘)\) 表示,那么我们只需要将所有二元组按照 \(x_i+x_i‘\) 排序,就一定不会错过最优解

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100005;

int n,m,t1,t2,t3;
vector <int> g[N];
struct pii {
    int x,y;
};
vector <pii> p;
double s,s2,ans=1e18,tans=0;

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++) {
        cin>>t1>>t2;
        g[t2].push_back(t1);
    }
    for(int i=1;i<=n;i++) {
        sort(g[i].begin(),g[i].end());
    }
    for(int i=1;i<=n;i++) {
        if(g[i].size()) {
            s+=g[i][0];
            s2+=g[i][0]*g[i][0];
        }
        for(int j=1;j<g[i].size();j++) {
            p.push_back({g[i][j-1],g[i][j]});
        }
    }
    sort(p.begin(),p.end(),[](pii a,pii b)->bool{return a.x+a.y<b.x+b.y;});
    ans=min(ans,s2-s*s/n);
    tans=s/n;
    for(int i=0;i<p.size();i++) {
        s-=p[i].x;
        s2-=p[i].x*p[i].x;
        s+=p[i].y;
        s2+=p[i].y*p[i].y;
        ans=min(ans,s2-s*s/n);
        if(fabs(s2-s*s/n-ans)<1e-6) tans=s/n;
    }
    printf("%.4lf",tans);
}

原文地址:https://www.cnblogs.com/mollnn/p/12655394.html

时间: 2024-11-08 23:09:11

[CQOI2012] 组装 - 贪心的相关文章

【BZOJ2666】[cqoi2012]组装 贪心

[BZOJ2666][cqoi2012]组装 Description 数轴上有m个生产车间可以生产零件.一共有n种零件,编号为1~n.第i个车间的坐标为xi,生产第pi种零件(1<=pi<=n).你需要在数轴上的某个位置修建一个组装车间,把这些零件组装起来.为了节约运输成本,你需要最小化cost(1)+cost(2)+…+cost(n),其中cost(x)表示生产第x种零件的车间中,到组装车间距离的平方的最小值. Input 输入第一行为两个整数n, m,即零件的种类数和生产车间的个数.以下m

BZOJ 2666 cqoi2012 组装 贪心

题目大意:给定数轴上的m个点,共有n种颜色,要求在数轴上选定一个点,使这个点到每种颜色最近的点的平方和最小 初始将所有颜色最左侧的点作为最近点,然后不断选择[当前点与同种颜色下一个点的中点最靠左的点]进行替换,并更新ans 理性证明见http://www.cnblogs.com/jianglangcaijin/p/4204478.html 下面来个感性证明: 这不是显然么- - 考虑将组装车间从-∞移动到+∞ 初始选择最左侧的点作为最近点 那么移动的过程中一旦车间离同种颜色的下一个点更近 那么当

BZOJ 2666: [cqoi2012]组装

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2666 题意:n种零件,m个位置,每个位置有一个零件.求一个位置x,使得cost(1)+cost(2)+…+cost(n)最小.cost(i)表示 x到最近的i类型零件的距离的平方. 思路:我们最后的最优答案一定从所有m个位置中选出了n个使得每种零件恰有一个.设第i种零件的所有位置集合是Si,Si的大小是Ci 我们可以直接枚举最后选出的第i种零件是哪一个,一旦确定了这n个零件.那么

NOJ1076 机器狗组装费用 贪心

题目描述 sed同学最近迷上了制造机器狗,购置了大量所需零件,零件可以组装为一个组件,这些组件或零件又可以组装为一个大的组件.在制造机器狗中,组件或零件只能两两进行组装,组装的顺序任意.在机器狗中,每个零件都有一个组装成本,每次组装一个组件的费用为各个零件组装成本之和.给定各个零件组装成本(单位为元),你的任务是帮助sed计算他至少花费多少费用. 输入 第一行包括一个整数N,表示机器狗零件数(1≤N≤10000) 第二行为N个正整数,表示每个机器狗零件组装成本(单位为元),整数之间用空格隔开.

LUOGU P3161 [CQOI2012]模拟工厂 (贪心)

传送门 解题思路 贪心,首先因为\(n\)比较小,可以\(2^n\)枚举子集.然后判断的时候就每次看后面的如果用最大生产力生产能不能达成目标,解一个二次函数. 代码 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define int long long using namespace std; const int

BZOJ 2667 cqoi2012 模拟工厂 贪心

题目大意:现在你有一个工厂,初始生产力为1,每一时刻你可以进行如下操作: 1.将生产力提高1 2.生产一些产品,数量等于当前生产力的数值 现在你有n个订单,每一份有一个交易时间t,一个商品数量g和一个价格m,可以接或者不接,如果接就要在t时刻操作之前减少g的商品数量,然后得到m的钱 求最大收益 跪shanest大爷... 由于n≤15,爆枚接受哪些订单 每次Check的时候,对于每段时间显然先提高生产力再生产产品 那么我可以考虑这一段内先尽量提高生产力 但是这样可能会导致生产力提高得太高而没有足

POJ3253 Fence Repair 小顶堆+贪心

给了你N个木棒,求把他们组装成一根需要的最小花费,每次只能选两根组装在一起,需要的花费为两个木棒之和, 以前遇到过把一整根切开的,那个是DP,这个则有些类似,可是大胆的猜测了一下,直接每次选取所有木棒中最短的两根,这样就可以了,那么贪心是适用的,但是数量很多,而且两根最短的组装好了得插回去,这样不可能每次都排序吧, 这题首先优先队列肯定是可以做的, 最小堆也是可以的,每次都选出堆里的最小的两个求和再放回去即可 队列本身也就是堆吧,所以差别不大,但是没用过最小堆最大堆的 所以用一次把 #inclu

贪心(qwq)习题题解

贪心(qwq)习题题解 SCOI 题解 [ SCOI2016 美味 ] 假设已经确定了前i位,那么答案ans一定属于一个区间. 从高位往低位贪心,每次区间查找是否存在使此位答案为1的值. 比如6位数确定了前三位\((101...)_2\),下一位应该是1 那么\(a_i+x_i\)的查找区间为:\([(101100)_2,(101111)_2]\) ,同理如果应该是0则为\([(101000)_2,(101011)_2]\). 注意到有区间\([l,r]\)范围的限制所以用主席树维护即可. [

8个节点,每个节点上布置6个ROS,组装都用250,读出都用251,事例率为645.3Hz

组装都用250网段,读出都用251网段.除了黄色部分以外的节点都是cmm03节点. 平均事例率为:645.26Hz, ros所在节点的cpu idle 为17%.