您的位置:首页 > 其它

洛谷1314 聪明的质监员

2017-08-26 23:39 211 查看

洛谷1314 聪明的质监员

原题链接

交题记录


23:28 AC

题还算水。



题解

10分算法

写挂的吧。。。

30分算法

暴力枚举统计答案???

50分算法

二分+暴力check。

AC算法

Y随W增加而减小,可以二分一个W。

\(W\in[0,10^6+1]\)

然后如何check

可以用到前缀和优化。

可以发现每一次check的前缀和是不同的,所以check一次就求一次前缀和。。。

怎么求?s表示\(>=w\)的数的和的前缀和,tot表示\(>=w\)的数个数的前缀和。

s即对应\(\sum_{j}v_j\),tot对应\(\sum_{j}1\).

每次\(O(n)\)求出s,tot后每个区间就可\(O(1)\)算了。

\(O(n+m)\)的check。

加上二分总复杂度\(O(log_210^6*(n+m))\)

注意:二分最后l==r-2,这样不会漏计答案(可能是我傻了)

Code

// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
#define rep(a,b,c) for(rg ll a=b;a<=c;a++)
#define drep(a,b,c) for(rg ll a=b;a>=c;a--)
#define erep(a,b) for(rg ll a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
typedef long long ll;
il ll gi(){
rg ll x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=200010;
ll n,m,S,w[maxn],v[maxn],L[maxn],R[maxn];
ll s[maxn],tot[maxn];
il ll check(int W){
rep(i,1,n){
s[i]=s[i-1],tot[i]=tot[i-1];
if(w[i]>=W)s[i]+=v[i],++tot[i];
}
ll ret=-S;
rep(i,1,m)ret+=(s[R[i]]-s[L[i]-1])*(tot[R[i]]-tot[L[i]-1]);
return ret;
}
int main(){
n=gi(),m=gi(),S=gi();
rep(i,1,n)w[i]=gi(),v[i]=gi();
rep(i,1,m)L[i]=gi(),R[i]=gi();
ll l=0,r=1000001,mid,ck;
while(l<r-2){
mid=l+r>>1;
ck=check(mid+1);
if(!ck){puts("0");return 0;}
if(check(mid+1)<0)r=mid+1;
else l=mid;
}
printf("%lld\n",min(abs(check(l+1)),min(abs(check(l)),abs(check(r)))));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: