codeforces 850B Arpa and a list of numbers

        题意:对于一个数组a[i],删去一个数字的代价为x,给一个数字+1的代价为y,求将整个数组的gcd变为不为1的最小代价。

        首先我们可以枚举这个数组的gcd,由于最差情况是删一个数字为5*10^5,+1代价为1,所以gcd最大可能为10^6,接着如果暴力判断每一个数字是n方的复杂度,接着我们可以对每一个数字进行分组。

        由于我们只能进行加法,所以我们可以将每[(j-1)*gcd+1,j*gcd]分为一组,他们如果要加肯定变成j*gcd最优,又因为我们最多加的次数为x/y,如果超过了这个x/y,删掉这个数的代价则会更小,所以我们就可以再将这个分组再分成两组[(j-1)*gcd+1,j*gcd-x/y-1],[j*gcd-x/y,j*gcd],对于第一组的数,我们将它直接删掉,第二组内的数字将它加到j*gcd,那么对于第一组数字,我们通过前缀和即可求出数字数量,答案*x即为这一组的花费,对于第二组的数字,我们可以也用前缀和的方法,求出这个区间内数字之和sum,以及数字个数cnt,那么他们要变成的数字之和为cnt*j*gcd,他们当前的和为sum,那么这组花费就是y*(cnt*j*gcd-sum)。

        最后枚举gcd求出最小花费的一种情况即可,由调和级数可以得到复杂度为nlogn.

        下附AC代码。

#include<iostream> 
#include<stdio.h> 
#include<string.h> 
#include<algorithm> 
#define maxn 2000005 
using namespace std; 
typedef long long ll; 
int n,maxx; 
ll x,y; 
ll cnt[maxn],sum[maxn]; 
int main() 
{ 
  scanf("%d%I64d%I64d",&n,&x,&y); 
  for(int i=1;i<=n;i++)   
  { 
    int t; 
    scanf("%d",&t); 
    maxx=max(t,maxx); 
    cnt[t]++; 
    sum[t]+=t; 
  } 
   
  for(int i=1;i<=2*1000000;i++) 
  cnt[i]+=cnt[i-1],sum[i]+=sum[i-1]; 
   
  ll ans=x*n; 
  for(int i=2;i<=1000000;i++) 
  { 
    ll now=0; 
    for(int j=i;j<=2*1000000;j+=i) 
    { 
      ll l=max((ll)j-i+1,j-(x/y)); 
      now+=y*(j*(cnt[j]-cnt[l-1])-(sum[j]-sum[l-1])); 
      now+=x*(cnt[l-1]-cnt[j-i]); 
    } 
    ans=min(ans,now); 
  } 
  printf("%I64d\n",ans); 
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值