CF850B Arpa and a list of numbers【思路】

来源:互联网 发布:生日祝福网页源码 编辑:程序博客网 时间:2024/05/19 16:32

题意:有一串数,我们用两个操作让它们的gcd不为1,1.直接删除,花费x,2.给它加一,花费y


思路:每个数都能分解成负数,我们枚举素数。关于操作的贪心:x小于等于y的话,直接删除;否则,计算x/y,可以加这么多个1,还不能满足条件的话,不如删除。

对于一个素数,有许多这样的区间[p,2p],我们考虑哪些数直接删除划算,哪些数+1到2p划算。分界点就是2p-x/y。用have[n] 记录前缀1~n中有几个数,sum[n] 记录have[n]中的这些数的和。

直接删除的数:区间起点 到 分界点前的那个点 中有几个数

加1的数:每个点都要加到2p,减去它们本来的值


#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<stdlib.h>#include<math.h>#include<vector>#include<list>#include<map>#include<stack>#include<queue>#include<algorithm>#include<numeric>#include<functional>using namespace std;typedef long long ll;typedef pair<int,int> pii;const int maxn = 1e6+5;ll have[maxn],sum[maxn];int vis[maxn]; int main(void){int n,x,y,s;while(scanf("%d%d%d",&n,&x,&y)!=EOF){memset(vis,0,sizeof vis);memset(have,0,sizeof have);memset(sum,0,sizeof sum);for(int i = 1; i <= n; i++){int a;scanf("%d",&a);have[a]++;sum[a]+=a;}for(int i = 2; i <= 1000000; i++){have[i] += have[i-1];sum[i] += sum[i-1];}s = x/y;ll ans = 0x3f3f3f3f3f3f3f3f; for(int i = 2; i <= 1000000; i++){if(vis[i]) continue;ll temp = 0;int j;for(j = i; j <= 1000000; j += i){vis[j] = 1;int p = max(j-i+1,j-s);temp += (have[p-1] - have[j-i]) * x;temp += ( (have[j] - have[p-1]) * j - (sum[j] - sum[p-1])) * y;}//以下3行,可以不特殊处理,只要把以上每个for循环的1000000 改成 2000000int p = max(j-i+1,j-s);temp += (have[min(p-1,1000000)] - have[j-i]) * x;temp += ( (have[1000000] - have[min(p-1,1000000)]) * j - (sum[1000000] - sum[min(p-1,1000000)])) * y;ans = min(ans,temp);}printf("%lld\n",ans);}return 0;}


阅读全文
0 0