本文主要是介绍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);
}
这篇关于codeforces 850B Arpa and a list of numbers的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!