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;
}