标签:没有 差分 algo 前缀 space getc clu ++i sum
有\(n\)个物品,每个的权值为\(a_i\)
定义正整数\(v\)为美丽的,当且仅当我们可以选取若干个物品使得其权值之和落在区间\([v,2v]\)中
求有多少个美丽的数
\(n\leq 10^5,a_i\leq 10^9\)
没想出正解,交的暴力还CE了。。菜的真实
可以考虑补集转换,也就是求出不美丽数,再用总数减去美丽数的个数
我们把每个物品转化为一个区间,这个区间所覆盖的数都是美丽数
(遇到这种值域极大的区间问题,就别想什么差分前缀和了,尝试用左右端点来表示一个区间)
我们可以把同时选择两个物品看做合并它们的两个区间
设此时有两个物品\(u,v(u<v)\),其代表的区间分别是\([\frac{u}{2},u],[\frac{v}{2},v]\)
若这两个区间相交,则合并出的新区间为\([\frac{u}{2},u+v]\),此时并没有不美丽数产生
若不相交,合并出的新区间同样是\([\frac{u}{2},u+v]\),但是此时有\(\frac{v}{2}-u\)个不美丽数产生(两者合并后的区间一定不会覆盖到这里,之后的区间也就更不会了)
可以发现,区间\(u,v\)合并后形成的新区间\(w\),既可以代表\(u\),也可以代表\(v\),也可以代表\(u+v\),因而这种计算方法是有结合律的
我们把区间按照右端点排序,计算不美丽数的个数即可
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int read();
int n;
int a[N];
int main() {
n = read();
for (int i = 1; i <= n; ++i) a[i] = read();
sort(a + 1, a + n + 1);
long long sum = 0, ans = 0, l = 0;
for (int i = 1; i <= n; ++i) {
l = (a[i] + 1) / 2;
ans += max(0LL, l - sum - 1);
sum += a[i];
}
printf("%lld\n", sum - ans);
return 0;
}
int read() {
int x = 0, c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
return x;
}
标签:没有 差分 algo 前缀 space getc clu ++i sum
原文地址:https://www.cnblogs.com/VeniVidiVici/p/11610083.html