codeforces 851D Arpa and a list of numbers

mac2022-06-30  116

目录

codeforces 851D Arpa and a list of numbers题意题解Code

codeforces 851D Arpa and a list of numbers

题目传送门

题意

给出\(n\)个数,有两种操作: 1.将一个数从数列中删除,代价为\(x\)。 2.将一个数加1,代价为\(y\)。 询问最少花费多少的代价能够使数列中所有数的\(Gcd\)不为1。\((1 \leq n \leq 5 \cdot 10^5 , 1 \leq x,y \leq 10^9 , 1 \leq a_i \leq 10^5)\)

题解

emm...这个题目似乎无论是CF上的题解还是各种网上的题解,都是那种利用\(x\)\(y\)之间的关系来求每个数最优的操作代价。但似乎这个题目还有一个乱搞的做法。。 首先我们肯定想到的是枚举\(1~1e6\)之内的所有素数,然后\(Check\)的贪心的进行选择(正解也是给予这个的)。但是这样的复杂度我们是接受不了的,于是我们就会不由自主地进行乱搞想更加优越的做法。首先我们会发现,无论怎样,让这所有的数的\(Gcd\)等于2似乎是个不错的选择,因为这样最劣的情况也只会对\(n\)个元素进行修改,所以我们刚开始的时候先\(Check\)一下2,作为当前最优的答案。然后由于复杂度的原因,我们不能枚举完所有的素数,那么怎么办?那我们就假装这个答案一定会是某个质因数,并且这个质因数在原来序列中出现过若干次,而出现的次数越多,那么作为最优答案的可能性也越大。这是为什么呢?我也不知道。。我们基于这个似乎不正确的结论,就可以贪心的进行\(Check\)了。先对于每一个数进行分解质因数,然后贪心的从出现次数由高到低进行枚举质因数进行\(Check\),大概\(Check\)个十多个就行了,这样我们至少就可以过了很多的数据了。至于为什么这个乱搞做法是正确的。。信息竞赛不需要证明。。只要觉得对就行了。。

啊啊啊哪个dalao来叉掉我啊,或者帮我证明一下啊。。。(逃

Code

#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e5+500; vector<int>pri; int n,x,y; ll res=2e18; int a[N]; struct Cnt { int idx,cnt; bool operator < (const Cnt &rhs) const { return cnt>rhs.cnt; } }C[2000005]; void Get(int x) { int c=x; for(int i=2;i*i<=c;i++) { if(c%i==0) C[i].cnt++; while(c%i==0) c/=i; } if(c>1) C[c].cnt++; } void Check(int G) { ll ans=0; for(int i=1;i<=n;i++) { if(a[i]%G==0) continue; if(x<=y) { ans+=1ll*x; } else { int s=a[i]%G; s=G-s; ans+=min(1ll*s*y,1ll*x); } } res=min(res,ans); } int main() { scanf("%d%d%d",&n,&x,&y); int Mx=0; for(int i=1;i<=1000000;i++) C[i].idx=i,C[i].cnt=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); Get(a[i]); } Check(2); sort(C+1,C+1000001); vector<int>tmp; tmp.clear(); for(int i=1;i<=10;i++) { if(C[i].cnt) tmp.push_back(C[i].idx); else break; } for(int i=0;i<(int)tmp.size();i++) { Check(tmp[i]); } printf("%lld\n",res); return 0; }

转载于:https://www.cnblogs.com/Apocrypha/p/9721270.html

最新回复(0)