BZOJ 4717: 改装【二分】

4717: 改装

【题目描述】
传送门

【题解】

我们看到题目肯定有一个想法,把n这个复杂度给优化掉。
我们可以二分答案,check(mid)去枚举b[]然后二分或前缀和找大于mid/b[]的值,就可以了。

代码如下

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
int n,m,a[250],b[100005],Sum[2005];
int aL,aR,bL,bR,K;
int read(){
    int ret=0;char ch=getchar();bool f=1;
    for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
    for(; isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-48;
    return f?ret:-ret;
}
bool cmp(int x,int y){return x>y;}
int Fnd(double x,int L,int R){
    int Ans=L-1,l=L;
    for(int mid=(R-L>>1)+L;L<=R;mid=(R-L>>1)+L)
    a[mid]>=x?Ans=mid,L=mid+1:R=mid-1;
    return Ans-l+1;
}
int check(int mid){
    int Ans=0;
    for(int i=bL;i<=bR;i++) Ans+=Sum[2000]-Sum[min(mid/b[i],2000)];
    return Ans;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("4717.in","r",stdin);
    freopen("4717.out","w",stdout);
    #endif
    n=read(),m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=m;i++) b[i]=read();
    int q=read();
    while(q--){
        int opt=read();
        if(opt){
            aL=read(),aR=read(),bL=read(),bR=read(),K=read();
            for(int i=0;i<=2000;i++) Sum[i]=0;
            for(int i=aL;i<=aR;i++) Sum[a[i]]++;
            for(int i=1;i<=2000;i++) Sum[i]+=Sum[i-1];
            int L=0,R=2e9,Ans=0;;
            for(int mid=(R-L>>1)+L;L<=R;mid=(R-L>>1)+L) if(check(mid)>=K) L=mid+1;else R=mid-1;
            printf("%d\n",L);
        }else{
            int Ty=read(),P=read(),k=read();
            if(Ty) b[P]=k;else a[P]=k;
        }
    }
    return 0;
}
posted @ 2018-07-07 10:37  XSamsara  阅读(93)  评论(0编辑  收藏  举报