codeforces 851 D. Arpa and a list of numbers(前缀和+bruteforce)

来源:互联网 发布:村上春树作品推荐知乎 编辑:程序博客网 时间:2024/05/20 07:37

题目链接

D. Arpa and a list of numbers

分析

是我太天真了,暴力枚举素数还是计算还是有问题的,复杂度太高,不过你可以发现只需要再处理一个前缀和就可以了….下面进入正题

首先显然可以想到枚举素数,那么最终就是对于每个素数的计算问题了,如果暴力计算的化肯定是要超时的,其实我们可以在O(1) 计算花费.

对于素数 k 来说,不为k 的倍数的数都要加到k 的倍数,所以只需要对每一个倍数区间计算就好,在 [ik,(i+1)k] 的区间内,显然只有ai+x/y(i+1)k 的数会加,其余都删除,因此,我们预处理一个前缀和sum 表示到[0,n] 的总个数

(sum[i+x/y1]sum[ik])x, 表示删除的花费,

那么加操作的花费呢?对于在 [ik,(i+1)k] 的区间内 满 足 ai+x/y(i+1)k 的数来说,它的花费是((i+1)kai)y,因此所有需要加的数的花费为

i=1s((i+1)kai)y=y(s(i+1)kai)

因此预处理一个关于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|1using 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;}
阅读全文
0 0
原创粉丝点击