CF_850B Arpa and a list of numbers

B. Arpa and a list of numbers

http://codeforces.com/problemset/problem/850/B

题意:
给定n个数,对每个数进行两种操作,使得剩下所有数的gcd不为1。
  1、删除一个数,花费x。
  2、增大一个数,每增加1,花费y。
求最小花费。
数据:
   n, x ,y (1 ≤ n ≤ 5·1e5, 1 ≤ x, y ≤ 1e9) 
思路:
1.枚举素数,可以按照每个数进行分块。
2.策略是 把每块内后 min( prime-1 , x/y ) 的数增加到该素数prime的倍数,之前的数全部删除。
3.用 前缀和 与 前缀个数 维护上述。
4.注意要多开一倍内存。
代码:
#include <cstdio>
#include <cstring>
#include <math.h>
#include <vector>
#include <algorithm>
#include <iostream>
#include <queue>
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long LL;
const LL N = 2050005; 
const LL M = 10921000; 
const LL INF = (1LL<<60); 
const LL MOD = 1e9+7;
const double eps = 1e-4;
LL n,m;
LL x,y;
LL s[N];
LL prime[N],vis[N];
LL pos=0;
void ini()
{
    pos=0;
    for (LL i=2;i<N;i++)
    {
        if (vis[i]==0)
            prime[pos++] = i;
        for (LL j=0;j<pos && i*prime[j]<N;j++)
        {
            vis[i*prime[j]] = 1;
            if (i%prime[j]==0)
                break;
        }
    }
}
LL num[N],sum[N];
int main()
{
    ini();
    while (~scanf("%I64d%I64d%I64d",&n,&x,&y))
    {
        memset(num,0,sizeof num);
        memset(sum,0,sizeof sum);
        LL ans = n*x;
        LL tmp = 0;
        LL ma = 0;
        for (LL i=0;i<n;i++)
        {
            LL a;
            scanf("%I64d",&a),ma = max(ma,a);
            num[a]++;
            sum[a] += a;
        }
        for (LL i=1;i<N;i++)
        {
            sum[i] += sum[i-1];
            num[i] += num[i-1];
        }
        for (LL i=0;i<pos;i++)
        {
            LL e = prime[i];
            tmp = 0;
            for (LL j=0;j*e<N/2;j++)
            {
                LL ct = min(e-1,x/y);
                tmp += x * (num[(j+1)*e-ct-1] - num[j*e]);
                tmp += y * ((num[(j+1)*e] - num[(j+1)*e-ct-1])*(j+1)*e - (sum[(j+1)*e] - sum[(j+1)*e-ct-1]));
            }
            ans = min(ans,tmp);
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

/*

4 23 17
1 17 17 16

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

*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值