NOIP2011 提高組 聰明的質監員(二分+字首和)
阿新 • • 發佈:2022-04-09
看到這道題,應該都能想到用二分,那問題是怎麼去判定呢?
我們考慮用字首和(a1統計w,a2統計v),列舉每個礦石,,當前判定的值是x,如果該礦石的w>=x,a1[i]=a1[i-1]+1,a2[i]=a2[i-1]+v[i];反之直接等於上一個就行了。
列舉完後,按照題目給的公式,更新它與s差值絕對值的最小值,得到最終答案。
#include<bits/stdc++.h> typedef long long LL; using namespace std; const int N=2e5+10; int n,m; LL s,sum,ans=0x3f3f3f3f3f3f3f3f,qzh1[N],qzh2[N];struct node{ int w,v; }a[N]; struct ask{ int l,r; }q[N]; bool check(int x){ LL res=0;sum=0; memset(qzh1,0,sizeof(qzh1)); memset(qzh2,0,sizeof(qzh2)); for(int i=1;i<=n;i++){ if(a[i].w>=x){ qzh1[i]=qzh1[i-1]+1; qzh2[i]=qzh2[i-1]+a[i].v; }else{ qzh1[i]=qzh1[i-1]; qzh2[i]=qzh2[i-1]; } } for(int i=1;i<=m;i++){ res+=(qzh1[q[i].r]-qzh1[q[i].l-1])*(qzh2[q[i].r]-qzh2[q[i].l-1]); } sum=llabs(res-s); if(res>s) return true; else return false; } int main(){ scanf("%d%d%lld",&n,&m,&s); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].w,&a[i].v); int h=0,t=1e6; for(int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r); while(h<=t){//二分答案 int mid=h+t>>1; if(check(mid)) h=mid+1; else t=mid-1; if(sum<ans) ans=sum;//更新答案 } cout<<ans; }
看到有區間,不一定要用資料結構去維護,有可能字首和更簡單些。