P1314 [NOIP2011 提高组] 聪明的质监员 二分 + 前缀和
作者:
多米尼克領主的致意
,
2024-05-05 17:07:21
,
所有人可见
,
阅读 9
此题难点在于前缀和的定义 只计算符合条件(w[i] > W)部分的前缀和
二分 + 前缀和
理解题意 容易得出 当W递增 则y递减 因为符合要求的矿产数量会减少
二分参数 W
此处的前缀和是非连续前缀和 以及 计数前缀和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, m;
ll s;
ll cnt[N], qzv[N];
ll sum;
int qjl[N], qjr[N];
ll ttt;
struct md{
int w, v;
}kc[N];
//bool cmp(md x, md y)
//{
// return x.w < y.w;
//}
bool check(int x)
{
// int l = 1, r = n;
// while(l < r)
// {
// int mid = (l + r) >> 1;
// if(kc[mid].w >= x)r = mid;
// else l = mid + 1;
// }
memset(cnt, 0, sizeof cnt);
memset(qzv, 0, sizeof qzv);
for(int i = 1;i <= n;i++)
{
if(kc[i].w >= x)cnt[i] = cnt[i - 1] + 1, qzv[i] = qzv[i - 1] + kc[i].v;
else cnt[i] = cnt[i - 1], qzv[i] = qzv[i - 1];
// cout << cnt[i] << " " << qzv[i] << endl;
}
ll y = 0;
for(int i = 1;i <= m;i++)
{
y += (cnt[qjr[i]] - cnt[qjl[i] - 1]) * (qzv[qjr[i]] - qzv[qjl[i] - 1]);
}
ttt = abs(s - y);
if(y <= s)return true;
return false;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> s;
for(int i = 1;i <= n;i++){
cin >> kc[i].w >> kc[i].v;
}
for(int i = 1;i <= m;i++)cin >> qjl[i] >> qjr[i];
int l = 1, r = 1000000;
ll ans = 0x3f3f3f3f3f3f3f3f;
while(l < r)
{
int mid = (l + r) >> 1;
if(check(mid))r = mid;
else l = mid + 1;
ans = min(ans, ttt);
}
cout << ans << endl;
return 0;
}
想请问下为什么
ans能在二分check函数内部统计答案吗
因为求的是abs(s - y)最小,就要把二分的值趋近于y = s这个点,这样最s - y接近0的左右两个点都能查找到(也可能是0本身)
ans可以在内部统计答案,因为这个分享也只是我平时做题的记录 所以习惯有点差hh.