品質監督の問題に対する巧妙な解決策[P1314]

トピックリンク

この品質監督遅かれ早かれ解雇します、そしてこのデータは、実際に水の問題で、私は2つのアプローチが、後に間違った場所を与えてみました......

ソリューション[NOIP2011]スマート品質監督

所与:タイトル効果\(N- \)鉱石番目、鉱石あたりの重量有する\(W \) および値の\(V \)を与え、\(M \)間隔\([L_iを、R_iを] \)間隔寄与定義\([L_iを、R_iを] \でY_I = \ sum_j1 \タイムズ\ sum_j v_J \クワッドJ \と\; w_j> Wが=ある\) 最適なパラメータを見つける\を(Wは\)ように\(\和Y \)できるだけ近い所与\(S \)

分析:理解するためにまず、この質問\(Y \)値は単調であるため、\(W \)が小さくなって、より多くの我々は、鉱石を選択することができますので、\(Y \)より大きい

そして、私たちは二部と思うに行くことができ、最初に私たちは、与えられた入力します\(W \)重いと昇順にソートし、その後、この場合、我々は最低見つけることができます\(W_i \)ように\(\合計Y \の当量をS \)場合、次に(\ Wは\)であるテイク(w_i-1 \)\場合SUM Y> S \)\(\(境界の場合、すなわち\(I = 1 \) 次いで満たさない)、時間我々は\(W_i \)\(W_ {I-1} \) 最適解を取るのに十分で

しかし、我々はしたい、問題に注意を払う(\ w)は\コレクションに挿入された\(INF \) ので、この質問は本当に水データである)、それはすべての鉱石の状況を表現することができるように、値が選択されていません

問題は(もあります脳のサプリメントパパの声)、カウントするためにどのように\(\ Y-SUM \)暴力の複雑さの言葉ならば、\(\)がnmに直接天国に(ツリーが会長を書き始め、半分だと思い書きました彼の平手打ちをポンピング)、我々驚き数は鉱石の条件を満たすことが見出されている、かどうか\(\和のV \)は、すべての接頭辞を最適化するために使用することができるので、単一の二分の複雑さを行うことができる\(N + m個\)のレベル

以下のように複雑\(O((N + M )\ログ、カード())W \)

\(\ CZ)真の神である、テーブル再生されない\(56msを\) ORZの外に実行する方法であります

// luogu-judger-enable-o2
#include <algorithm>
#include <cstdio>
#include <cctype>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 100;
inline ll read(){
    ll x = 0;char c = getchar();
    while(!isdigit(c))c = getchar();
    while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    return x;
}
struct Seg{int l,r;}seg[maxn];
struct Stone{int w,v;}stone[maxn];
ll sum_cnt[maxn],sum_v[maxn],w[maxn],s;
int n,m,l = 0x7fffffff,r = -0x7fffffff,tmp;
ll solve(int w){
    ll res = 0;
    for(int i = 1;i <= n;i++)
        if(stone[i].w >= w)sum_cnt[i] = sum_cnt[i - 1] + 1,sum_v[i] = sum_v[i - 1] + stone[i].v;
        else sum_cnt[i] = sum_cnt[i - 1],sum_v[i] = sum_v[i - 1];
    for(int i = 1;i <= m;i++)
        res += (sum_cnt[seg[i].r] - sum_cnt[seg[i].l - 1]) * (sum_v[seg[i].r] - sum_v[seg[i].l - 1]);
    return res;
}
int main(){
    n = read(),m = read(),s = read();
    for(int i = 1;i <= n;i++)
        w[i] = stone[i].w = read(),stone[i].v = read();
    for(int i = 1;i <= m;i++)
        seg[i].l = read(),seg[i].r = read();
    w[n + 1] = 0x7fffffff;//插入一个INF代表所有矿石都不选
    sort(w + 1,w + 2 + n);
    int siz = unique(w + 1,w + 2 + n) - w - 1;//去重 + 排序
    l = 1,r = siz;
    while(l <= r){
        int mid = (l + r) >> 1;
        if(solve(w[mid]) <= s)tmp = mid,r = mid - 1;
        else l = mid + 1;
    }
    ll ans = min(abs(solve(w[tmp]) - s),abs(solve(w[tmp - 1]) - s));//取最优
    return printf("%lld\n",ans),0;
}

おすすめ

転載: www.cnblogs.com/colazcy/p/11515137.html