Luogu3162 CQOI2012 组装 贪心

传送门


如果提供每一种零件的生产车间固定了,那么总时间\(t\)与组装车间的位置\(x\)的关系就是

\(t = \sum (x-a_i)^2 = nx^2-2\sum a_ix + \sum a_i^2\)

而显然的一点,提供某一种零件的生产车间一定会是\(|x-a_i|\)最小的那个\(i\),所以如果一个生产车间\(i\)会向组装车间提供零件,那么对应的\(x\)会在一段区间之内。

把这些区间拿出来,从左往右扫一遍,这个过程中记录提供每一种零件的生产车间的变化并动态维护\(\sum a_i\)\(\sum a_i^2\)以及\(x\)的取值范围,这样就可以算出当前状态下组装车间的最优选址。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    bool f = 0;
    while(!isdigit(c) && c != EOF){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    if(c == EOF)
        exit(0);
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return f ? -a : a;
}

#define ld long double
#define PLI pair < ld , int >
const int MAXN = 10010;
vector < int > lj[MAXN];
int N , M , p[MAXN];
priority_queue < PLI > q;

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    N = read();
    M = read();
    ld pre = -1e40 , cur = -1e40 , sum = 0 , pfh = 0 , ans = 1e40 , minInd;
    for(int i = 1 ; i <= M ; ++i){
        int a = read() , b = read();
        lj[b].push_back(a);
    }
    for(int i = 1 ; i <= N ; ++i){
        sum += lj[i][0];
        pfh += 1ll * lj[i][0] * lj[i][0];
        if(lj[i].size() > 1)
            q.push(PLI(-(lj[i][1] + lj[i][0]) / 2.0 , i));
    }
    while(!q.empty()){
        PLI t = q.top();
        q.pop();
        pre = cur;
        cur = -t.first;
        int i = t.second;
        ld minN = sum / N;
        if(pre > minN){
            if(ans > N * pre * pre - 2 * sum * pre + pfh){
                ans = N * pre * pre - 2 * sum * pre + pfh;
                minInd = pre;
            }
        }
        else
            if(cur < minN){
                if(ans > N * cur * cur - 2 * cur * sum + pfh){
                    ans = N * cur * cur - 2 * cur * sum + pfh;
                    minInd = cur;
                }
            }
            else
                if(ans > (N * pfh - sum * sum) / N){
                    ans = (N * pfh - sum * sum) / N;
                    minInd = minN;
                }
        sum -= lj[i][p[i]];
        pfh -= 1ll * lj[i][p[i]] * lj[i][p[i]];
        sum += lj[i][++p[i]];
        pfh += 1ll * lj[i][p[i]] * lj[i][p[i]];
        if(p[i] + 1 != lj[i].size())
            q.push(PLI(-(lj[i][p[i] + 1] + lj[i][p[i]]) / 2.0 , i));
    }
    pre = cur;
    cur = 1e40;
    ld minN = sum / N;
    if(pre > minN){
        if(ans > N * pre * pre - 2 * sum * pre + pfh){
            ans = N * pre * pre - 2 * sum * pre + pfh;
            minInd = pre;
        }
    }
    else
        if(cur < minN){
            if(ans > N * cur * cur - 2 * cur * sum + pfh){
                ans = N * cur * cur - 2 * cur * sum + pfh;
                minInd = cur;
            }
        }
        else
            if(ans > (N * pfh - sum * sum) / N){
                ans = (N * pfh - sum * sum) / N;
                minInd = minN;
            }
    cout << fixed << setprecision(4) << minInd;
    return 0;
}

转载于:https://www.cnblogs.com/Itst/p/10341948.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值