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 美妙的购物的主要内容,如果未能解决你的问题,请参考以下文章

RK3399平台开发系列讲解(内核调试篇)9.30如何在Linux kernel代码中获取当前进程的信息

作业9.30

9.30

9.30notes

Vue实现购物小球抛物线的方法实例

9.30