题目链接
分析
是我太天真了,暴力枚举素数还是计算还是有问题的,复杂度太高,不过你可以发现只需要再处理一个前缀和就可以了….下面进入正题
首先显然可以想到枚举素数,那么最终就是对于每个素数的计算问题了,如果暴力计算的化肯定是要超时的,其实我们可以在 O(1) 计算花费.
对于素数
k
来说,不为
(sum[i+⌊x/y⌋−1]−sum[i∗k])∗x , 表示删除的花费,
那么加操作的花费呢?对于在 [i∗k,(i+1)∗k] 的区间内 满 足 ai+⌊x/y⌋≥(i+1)∗k 的数来说,它的花费是 ((i+1)∗k−ai)∗y ,因此所有需要加的数的花费为
因此预处理一个关于 ai 值的前缀和就好了, O(1) 计算,总复杂度 nlog(n)
ac code
#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define ms(x,v) memset((x),(v),sizeof(x))
#define scint(x) scanf("%d",&x );
#define scf(x) scanf("%lf",&x );
#define eps 1e-10
#define dcmp(x) (fabs(x) < eps? 0:((x) <0?-1:1))
#define lc o<<1
#define rc o<<1|1
using namespace std;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> Pair;
const int maxn = 2e6+10;
const int MAX_V= 500+10;
const int MOD = 998244353;
int prime[maxn],cnt;
void init(){
cnt =0;
memset(prime,0,sizeof(prime));
for(int i = 2 ; i<maxn ; ++i){
if(!prime[i]){
prime[cnt++] = i;
}
for(int j=0 ; j<cnt && i*prime[j]<maxn ; ++j){
prime[i*prime[j]] = 1;
if(i%prime[j] == 0) break;
}
}
}
LL a[maxn],p[maxn];
LL sum[maxn];
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
init();
int n,x,y;
ms(a,0);
cin>>n>>x>>y;
int maxv =0;
for(int i=0 ; i<n ; ++i){
int tmp;
cin>>tmp;a[tmp]++;
maxv = max(maxv,tmp);
}
sum[0] =0;
p[0] =0;
for(int i=1 ; i<maxn ; ++i){
sum[i] = sum[i-1] + a[i];
p[i]+= p[i-1] +a[i]*i;
}
LL ans =1e18;
int t = x/y;
for(int j =0 ; j<cnt&& prime[j] <= 2*maxv; ++j){
int k = prime[j];
LL res =0;
for(int i = k ; i<maxn&&i<=2*maxv; i+=k){
int bound = min(t,k-1);
res += (sum[i-bound-1] - sum[i-k])*x;
if(res >= ans)break;
LL s = sum[i-1] - sum[i-bound-1];
res += (s*i - (p[i-1] - p[i - bound - 1]))*y;
}
ans = min(res,ans);
}
std::cout << ans << '\n';
//std::cout << "time "<< clock()/1000 <<"ms"<< '\n';
return 0;
}