CF850B Arpa and a list of numbers【思路】

题意:有一串数,我们用两个操作让它们的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 改成 2000000
			int 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值