zoukankan      html  css  js  c++  java
  • P1314 [NOIP2011 提高组] 聪明的质监员

    一开始的想法是二分(|s-y|)的值t,然后根据二分到的值,看是否能够找到一个W,使(s-tle yle s + t),并且答案具有二段性,因为如果对于t能够找到一个W使得满足条件,那么所有比t大的值,都能够满足存在W使得(s-tle yle s + t),所以满足二段性,由于是整数二分,一定能够找到一个最小的t使得(|s - y|=t),但是这样的话,没想到怎么去求W...

    思路:二分W,如果W的值使得s - y > 0,为了让|s - y|更小,应该让W小一些,如果W的值使得s - y <= 0,为了让|s - y|更小,应该让W大一些,在二分过程中求出(|s-y|)最小值(和之前做的二分有些区别,不是直接二分答案),另外,因为有区间求和,所以再算s - y的时候要用前缀和优化一下

    #include<iostream>
    #include<cstring>
    using namespace std;
    
    #define LL long long
    
    const int N = 200010;
    
    int n, m;
    LL s, ans = 1e12 + 10;
    int w[N], v[N], l[N], r[N];
    LL a[N], b[N];
    
    LL check(LL W){
        memset(a, 0, sizeof a);
        memset(b, 0, sizeof b);
        
        for(int i = 1; i <= n; i ++){
            if(w[i] >= W) a[i] += a[i - 1] + 1, b[i] += b[i - 1] + v[i];
            else a[i] = a[i - 1], b[i] = b[i - 1];
        }
        LL res = 0;
        for(int i = 1; i <= m; i ++)
            res += (a[r[i]] - a[l[i] - 1]) * (b[r[i]] - b[l[i] - 1]);
            
        return s - res;
    }   
    
    int main(){
        cin >> n >> m >> s;
        for(int i = 1; i <= n; i ++) cin >> w[i] >> v[i];
        for(int i = 1; i <= m; i ++) cin >> l[i] >> r[i];
        LL ll = 0, rr = 1e6;
        while(ll < rr){
            LL mid = ll + rr >> 1;
            LL val = check(mid);
            if(val > 0) rr = mid;
            else ll = mid + 1;
            ans = min(ans, abs(val));
        }
        
        cout << ans << endl;
        
        return 0;
    }
    
  • 相关阅读:
    软件工程第一次作业
    软工热身作业
    OO第四单元
    面向对象——规格总结
    OO电梯作业总结
    JAVA实现表达式求导运算的分析总结
    提问回顾与个人总结
    Flutter的环境配置以及一些常见问题
    软件案例分析
    软件工程结对作业
  • 原文地址:https://www.cnblogs.com/tomori/p/15264789.html
Copyright © 2011-2022 走看看