1. 程式人生 > 其它 >NOIP2011 提高組 聰明的質監員(二分+字首和)

NOIP2011 提高組 聰明的質監員(二分+字首和)

看到這道題,應該都能想到用二分,那問題是怎麼去判定呢?

我們考慮用字首和(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; }

看到有區間,不一定要用資料結構去維護,有可能字首和更簡單些。