zoukankan      html  css  js  c++  java
  • 洛谷 P1314 聪明的质监员 —— 二分

    题目:https://www.luogu.org/problemnew/show/P1314

    显然就是二分那个标准;

    当然不能每个区间从头到尾算答案,所以要先算出每个位置被算了几次;

    不知为何自己第一想法是把符合要求的位置插入树状数组再遍历区间得到该区间内的个数然后在其左右端点差分最后遍历位置时一边计算每个位置的次数;

    但其实用前缀和就可以了...而且前缀和比上面那个快好多...

    调了好半天,才发现 ans 的初值不能习惯性地赋成 0x3f3f3f3f,那个才是个 int 范围内的...

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define mid ((L+R)>>1)
    using namespace std;
    typedef long long ll;
    int const maxn=2e5+5;
    int n,m,mx,w[maxn],v[maxn],f[maxn],l[maxn],r[maxn],d[maxn],num[maxn];
    ll ans,s,sum[maxn];
    ll rd()
    {
        ll ret=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
        while(ch>='0'&&ch<='9')ret=(ret<<3ll)+(ret<<1ll)+ch-'0',ch=getchar();
        return f?ret:-ret;
    }
    void add(int x){for(;x<=n;x+=(x&-x))f[x]++;}
    int query(int x){int ret=0; for(;x;x-=(x&-x))ret+=f[x]; return ret;}
    ll work(int x)
    {
        ll ret=0;
    //    memset(f,0,sizeof f);
    //       memset(d,0,sizeof d);
    //    for(int i=1;i<=n;i++)if(w[i]>=x)add(i);
    //    for(int i=1;i<=m;i++)
    //    {
    //        int k=query(r[i])-query(l[i]-1);
    //        printf("l=%d r=%d k=%d
    ",l[i],r[i],k);
    //        d[l[i]]+=k; d[r[i]+1]-=k;
    //    }
    //    for(int i=1,nw=0;i<=n;i++)
    //    {
    //        nw+=d[i];
    //        if(w[i]>=x)ret+=(ll)v[i]*nw;
    //        printf("i=%d ret=%lld
    ",i,ret);
    //    }
        memset(sum,0,sizeof sum);
        memset(num,0,sizeof num);
        for(int i=1;i<=n;i++)
        {
            num[i]=num[i-1]+(w[i]>=x);
            sum[i]=sum[i-1]+(w[i]>=x?v[i]:0);
    //        printf("num[%d]=%d sum[%d]=%d
    ",i,num[i],i,sum[i]);
        }
        for(int i=1;i<=m;i++)
            ret+=(sum[r[i]]-sum[l[i]-1])*(num[r[i]]-num[l[i]-1]);
        return ret;
    }
    int main()
    {
        n=rd(); m=rd(); s=rd();
        for(int i=1;i<=n;i++)w[i]=rd(),v[i]=rd(),mx=max(mx,w[i]);
        for(int i=1;i<=m;i++)l[i]=rd(),r[i]=rd();
        int L=0,R=mx+1; ans=1e13;
        //ans=inf;
        while(L<=R)
        {
            ll ret=work(mid);
    //        printf("ret=%lld mid=%d L=%d R=%d
    ",ret,mid,L,R);
            if(ret>=s)
            {
    //            if(ans<=ret-s)break;
                ans=min(ans,ret-s); L=mid+1;
            }
            else
            {
    //            if(ans<=s-ret)break;
                ans=min(ans,s-ret); R=mid-1;
            }
    
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    poj3984 迷宫问题(简单搜索+记录路径)
    substr
    poj3087 Shuffle'm Up
    学生管理系统
    win10配置gcc编译环境
    poj3278 Catch That Cow
    将字符串str1复制为字符串str2的三种解决方法
    poj2251 Dungeon Master
    cf 410
    7.20 Codeforces Beta Round #8
  • 原文地址:https://www.cnblogs.com/Zinn/p/9686785.html
Copyright © 2011-2022 走看看