zoukankan      html  css  js  c++  java
  • Codeforces Codeforces Round #432 (Div. 2 D ) Arpa and a list of numbers

    D. Arpa and a list of numbers


    time limit per test   2 seconds

    memory limit per test     256 megabytes


    Arpa has found alist containingn numbers. Hecalls a list bad if and only if it is not empty and gcd (see notes section for more information) of numbers in the list is 1.

    Arpa can performtwo types of operations:

    ·  Choose a number and delete it with cost x.

    ·  Choose a number and increase it by 1 with cost y.

    Arpa can applythese operations to as many numbers as he wishes, and he is allowed to applythe second operation arbitrarily many times on the same number.

    Help Arpa tofind the minimum possible cost to make the list good.

    Input

    First linecontains three integersn,x and y (1 ≤ n ≤ 5·105,1 ≤ x, y ≤ 109) — the number of elements in the list and the integers x and y.

    Second linecontainsn integers a1, a2, ..., an (1 ≤ ai ≤ 106) — the elements of the list.

    Output

    Print a single integer: the minimumpossible cost to make the list good.

    Examples

    Input

    4 23 17
    1 17 17 16

    Output

    40

    Input

    10 6 2
    100 49 71 73 66 96 8 60 41 63

    Output

    10

    Note

    In example,number1 must be deleted (with cost 23) and number 16 must increased by 1 (with cost 17).

    Agcd (greatest common divisor) of a set of numbers is the maximum integer thatdivides all integers in the set. Read more about gcdhere.

    【题意】

    给出n个数,以及x,y。现在你可以对这n个数进行两种操作。

    1. 把任意一个数删除,花费为x。
    2. 把任意一个数加一,花费为y。

    现在要求操作后所有数gcd不为1(不互质),求最小花费。

    【思路】

    显然可以想到去枚举gcd,考虑到时间上的优化,我们可以枚举素数,因为每个不为1的数一定是一个素数或者一个素数的倍数。(事实上直接暴力枚举gcd也能卡过)

    素数用素筛预处理一下即可。

    假设我们枚举的素数为prime。那么我们需要把所有数变为这个素数或其倍数或者将其中一个(或几个)删除。

    显然如果我们要改变某个数的值,我们一定是增加到离它最近的是prime的倍数的那个数。所以我们应该提前预处理一下前缀和sum[i]、num[i],sum[i]表示小于等于i的数的和,num[i]表示小于等于i的数的个数,然后在区间内进行操作。

    假设现在枚举的区间为【 k * prime[i] , (k+1) * prime[i]),那么我们先应该在区间内找一个分界点limit,一个数小于等于limit时删除它花费更少,否则把它一直加到k * prime[i]的花费更少。

    limit可由x,y的大小得到。

    limit=max( (j+1) * prime[i]-rate-1 , j * prime[i]);

    然后就对区间里的数根据limit分成的两部分分别计算。

    对于删除的那部分,计算方法为删除个数*x,即:

    num[ limit ]-num[ j * prime[i]] * x

    而对于加上的那部分,计算方法为(数的个数*加上后所得到的那个素数的倍数-原来的数的和) * y,即:

    ((num[(j+1) * prime[i]]-num[limit]) * ((j+1) * prime[i])-(sum[(j+1) * prime[i]]-sum[limit])) * y

    然后不断更新最小值即可。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define mst(a,b) memset((a),(b),sizeof(a))
    #define rush() int T;scanf("%d",&T);while(T--)
    
    typedef long long ll;
    const int maxn = 1000005*2;
    const ll mod = 1e9+7;
    const int INF = 0x3f3f3f3f;
    const double eps = 1e-6;
    
    int prime[maxn]= {0};
    int num_prime=0;
    bool isprime[maxn]= {1,1}; 
    ll num[maxn],sum[maxn];
    
    
    void init()
    {
        for(int i=2;i<maxn;i++)
        {
            if(!isprime[i]) prime[num_prime++]=i;
            for(int j=0;j<num_prime&&i*prime[j]<maxn;j++)
            {
                isprime[i*prime[j]]=1;
                if(i%prime[j]==0)   break;
            }
        }
    }
    
    int main()
    {
        int o;
        int n,x,y;
        init();
        while(~scanf("%d%d%d",&n,&x,&y))
        {
            mst(num,0);
            mst(sum,0);
            int Max=0;
            for(int i=0;i<n;i++)
            {
                scanf("%d",&o);
                num[o]++;
                sum[o]+=o;
                Max=max(Max,o);
            }
            for(int i=1;i<=Max*2;i++)          //预处理前缀和
            {
                num[i]+=num[i-1];
                sum[i]+=sum[i-1];
            }
            int rate=x/y;
            ll ans=1e18;
            for(int i=0;i<num_prime&&prime[i-1]<=Max;i++)
            {
                ll cnt=0;
                for(int j=0;j*prime[i]<=Max;j++)
                {
                    int limit=max((j+1)*prime[i]-rate-1,j*prime[i]);
                    ll num1=num[limit]-num[j*prime[i]];             //删除
                    ll sum2=sum[(j+1)*prime[i]]-sum[limit];         //加上
                    ll num2=num[(j+1)*prime[i]]-num[limit];
                    cnt+=num1*x;
                    cnt+=(num2*((j+1)*prime[i])-sum2)*y;
                    if(cnt>ans) break;                              //优化
                }
                ans=min(ans,cnt);
            }
            printf("%I64d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    数据库: Android使用JDBC连接数据库实现增 删 该 查 操作(8.0版本)
    SWA2G422&485JK2G基础篇: 手机APP通过APMACBind方式绑定W5500(以太网)设备,实现MQTT远程通信控制
    ESA2GJK1DH1K微信小程序篇: 微信小程序MQTT连接阿里云物联网平台
    ESA2GJK1DH1K基础篇: 阿里云物联网平台: 测试MQTT连接阿里云物联网平台
    ESA2GJK1DH1K微信小程序篇: 小程序MQTT底层优化
    ESP8266 SDK开发: 准备工作-硬件说明
    ESA2GJK1DH1K数据篇: 数据篇准备工作
    ESA2GJK1DH1K升级篇: 网页实现MQTT控制- 网页版MQTT通信控制ESP8266设备,网页版MQTT连接阿里云通信
    ESA2GJK1DH1K升级篇: 网页实现MQTT控制- 网页版MQTT调试助手
    单片机模块化程序: CRC校验
  • 原文地址:https://www.cnblogs.com/Aragaki/p/7482425.html
Copyright © 2011-2022 走看看