zoukankan      html  css  js  c++  java
  • [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);
    }
    
    
  • 相关阅读:
    《面向对象编程》c++ primer 第15章
    extern的作用(综合网络)
    C程序内存区域分配(5个段作用)
    鼓舞自己的名言
    快速指数算法 和 求逆元算法
    HP Xeon 55xx上GPU的带宽问题
    Ubuntu12.04 安装ibusfbterm0.9.1
    Win7下读写Ext2/Ext3/Ext4文件系统
    fbv安装 为console添加背景图片
    CentOS6/7安装fcitx4.2.5
  • 原文地址:https://www.cnblogs.com/mollnn/p/12655394.html
Copyright © 2011-2022 走看看