您的位置:首页 > 其它

Codeforces Round #432 (Div. 2) D 850B Arpa and a list of numbers(gcd 枚举)

2017-09-06 07:24 573 查看
一看到感觉是dp,但是dp也太难了呀,然后就滚了.

gcd的问题很多时候都是枚举,因为gcd其实是很难递推的一个东西,所以观察一下ai的范围,大概也能猜到.

那么我们枚举每一个gcd,当然,是素数啦,然后发现每一个gcd我们数列的值可以O(n)算出来,可是素数有很多,这样不够,那么我们怎么样更快呢,就是可以利用一个区间的思想,假设x/y=delta,也就是说,假设p是gcd的一个倍数,那么在p-delta~p的范围内的数,他们要变成p,而在p-gcd~p-delta-1范围内的数,就是要删除,对吧?所以我们预处理一下,就可以在O(1)内得到要删除的数字数量和要加的数字之和(注意两者不同,要处理两个数组).感觉这里很奇妙的就是以前的前缀和都是以下标来做数组,但是这里直接是以值来做数组,这样好处就是假如用下标,那么要找到是logn,但这里ai小,所以直接用,可以O(1)得到,第一次见呢.

(感觉D题还是太难了,我还是太菜了,写起来真的各种难,留下我丑陋的调试痕迹好了)

/*  xzppp  */
#include <iostream>
#include <vector>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <string>
#include <cmath>
#include <bitset>
#include <iomanip>
using namespace std;
#define FFF freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define MP make_pair
#define PB push_back
typedef long long  LL;
typedef unsigned long long ULL;
typedef pair<int,int > pii;
typedef pair<double,double > pdd;
typedef pair<double,int > pdi;
const int MAXN = 1e6+17;
const int MAXM = 20;
const int MAXV = 2*1e3+17;
const int INF = 0x7fffffff;
const LL INFF = 0x7fffffffffffffff;
const int MOD = 1e9+7;
LL prime[MAXN];
LL vis[MAXN];
LL cnt;
void get(){
memset(vis, 0, sizeof(vis));
cnt=0;
for(int i=2;i<MAXN;i++){
if(!vis[i]){
prime[++cnt]=i;
for(int j=i+i;j<MAXN;j+=i){
vis[j]=1;
}
}
}
}
LL a[2*MAXN],c[2*MAXN],tms[2*MAXN],sum[2*MAXN];
int main()
{
#ifndef ONLINE_JUDGE
FFF
#endif
get();
LL n,x,y,gst= 0 ;
cin>>n>>x>>y;
for (int i = 0; i < n; ++i)
{
scanf("%lld",a+i);
tms[a[i]]++;
sum[a[i]]+=a[i];
gst = max(gst,a[i]);
}
for (int i = 1; i <= 2*MAXN; ++i)
{
tms[i]+=tms[i-1];
sum[i]+=sum[i-1];
}
LL ans = INFF,delta = x/y,ori = delta;
for (int i = 1; i <= cnt; ++i)
{
//cout<<prime[i]<<endl;
if(prime[i]>2*gst) break;
LL p = prime[i];
LL del=0,inc=0,sinc=0,temp=0;
for (LL j = p; j <= gst+p; j+=p)
{
if(delta<p-1)
{
del =  tms[j-delta-1] - tms[j-p];
inc =  sum[j-1] - sum[j-delta-1];
sinc = tms[j-1] - tms[j-delta-1];
//if(del<0) cout<<j-delta-1<<" asd "<<j-p<<endl;
}
else
{
inc = sum[j-1] - sum[j-p];
sinc = tms[j-1] - tms[j-p];
//if(inc<0) cout<<j-1<<" sec "<<j-p<<endl;
//cout<<j<<"  "<<inc<<"  "<<sinc<<endl;
}
//cout<<j<<"  "<<del<<"  "<<inc<<"  "<<sinc<<endl;
temp += del*x+(sinc*j-inc)*y;
//cout<<temp<<endl;
}
//LL temp = del*x + (sinc*p-inc)*y;
//cout<<"ans"<<temp<<endl;
ans = min(temp,ans);
}
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces acm