9.30 美妙的购物
Posted venividivici
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9.30 美妙的购物相关的知识,希望对你有一定的参考价值。
题意
有(n)个物品,每个的权值为(a_i)
定义正整数(v)为美丽的,当且仅当我们可以选取若干个物品使得其权值之和落在区间([v,2v])中
求有多少个美丽的数
(nleq 10^5,a_ileq 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
", 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;
}
以上是关于9.30 美妙的购物的主要内容,如果未能解决你的问题,请参考以下文章