洛谷1314 聪明的质监员

洛谷1314 聪明的质监员


原题链接


交题记录

23:28 AC
题还算水。


题解

10分算法

写挂的吧。。。

30分算法

暴力枚举统计答案???

50分算法

二分+暴力check。

AC算法

Y随W增加而减小,可以二分一个W。
\(W\in[0,10^6+1]\)
然后如何check
可以用到前缀和优化。
可以发现每一次check的前缀和是不同的,所以check一次就求一次前缀和。。。
怎么求?s表示\(>=w\)的数的和的前缀和,tot表示\(>=w\)的数个数的前缀和。
s即对应\(\sum_{j}v_j\),tot对应\(\sum_{j}1\).
每次\(O(n)\)求出s,tot后每个区间就可\(O(1)\)算了。
\(O(n+m)\)的check。
加上二分总复杂度\(O(log_210^6*(n+m))\)
注意:二分最后l==r-2,这样不会漏计答案(可能是我傻了)


Code

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
#define rep(a,b,c) for(rg ll a=b;a<=c;a++)
#define drep(a,b,c) for(rg ll a=b;a>=c;a--)
#define erep(a,b) for(rg ll a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il ll gi(){
    rg ll x=0,f=1;rg char ch=getchar();
    while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
const int maxn=200010;
ll n,m,S,w[maxn],v[maxn],L[maxn],R[maxn];
ll s[maxn],tot[maxn];
il ll check(int W){
    rep(i,1,n){
        s[i]=s[i-1],tot[i]=tot[i-1];
        if(w[i]>=W)s[i]+=v[i],++tot[i];
    }
    ll ret=-S;
    rep(i,1,m)ret+=(s[R[i]]-s[L[i]-1])*(tot[R[i]]-tot[L[i]-1]);
    return ret;
}
int main(){
    n=gi(),m=gi(),S=gi();
    rep(i,1,n)w[i]=gi(),v[i]=gi();
    rep(i,1,m)L[i]=gi(),R[i]=gi();
    ll l=0,r=1000001,mid,ck;
    while(l<r-2){
        mid=l+r>>1;
        ck=check(mid+1);
        if(!ck){puts("0");return 0;}
        if(check(mid+1)<0)r=mid+1;
        else l=mid;
    }
    printf("%lld\n",min(abs(check(l+1)),min(abs(check(l)),abs(check(r)))));
    return 0;
}
posted @ 2017-08-26 23:39  菜狗xzz  阅读(130)  评论(0编辑  收藏  举报