传送门:洛谷 P1314 聪明的质监员
算法分析:
调整参数\(W\)的值,让检验结果尽可能的靠近标准值\(S\),即使得\(|S-Y|\)最小。请你帮忙求出这个最小值。
其中 \(Y_i=\sum_j1\times\sum_jv_j, j\in[L_i,R_i] \ \cap \ w_j\geq W\)
不难发现,当\(W\)增大时,\(Y\)一定随之增大,这题可用二分的思想:即二分\(W\),计算出\(Y\)值(前缀和优化)
绝对值的处理:
如图所示的是 \(y=|x-3|\) 的函数图像
不难发现,图像以 \((3,0)\) 为界,左侧单调减,右侧单调增,两侧单调性不同
故若要求 \(|S-Y|\) 的最小值,要从两旁逼近:
1、\(S<Y\),\(S\) 应增大
2、\(S>Y\), \(S\) 应减小
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxN=200000;
const long long inf=0x7ffffffffffffff;
struct Node
{
int v,w;
}a[maxN+1];
inline int read();
int n,m,box[maxN+1][2],L=999999999,R=0;;
long long S,ans=inf,b[maxN+1],c[maxN+1],sum;
bool calc(int);
int main()
{
n=read(); m=read(); scanf("%lld",&S);
for(int i=1;i<=n;i++)
{
a[i].w=read();
a[i].v=read();
L=min(L,a[i].w); R=max(R,a[i].w);
}
for(int i=1;i<=m;i++)
{
int x=read();
int y=read();
box[i][0]=x; box[i][1]=y;
}
int l=L-1,r=R+1;
while(l<=r)
{
int mid=(l+r)/2;
if(calc(mid)) l=mid+1;
else r=mid-1;
ans=min(ans,abs(S-sum));
}
printf("%lld",ans);
return 0;
}
bool calc(int W)
{
sum=0;
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
if(a[i].w<W) {b[i]=b[i-1]; c[i]=c[i-1];}
else {b[i]=b[i-1]+a[i].v; c[i]=c[i-1]+1;}
for(int i=1;i<=m;i++)
sum+=(b[box[i][1]]-b[box[i][0]-1])*(c[box[i][1]]-c[box[i][0]-1]);
if(sum>S) return true;
else return false;
}
inline int read()
{
int num=0,f=1;
char ch=getchar();
while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if(ch=='-') {f=-1; ch=getchar();}
while(ch>='0' && ch<='9')
{
num=num*10+ch-'0';
ch=getchar();
}
return num*f;
}