Codeforces Round #511 (Div. 2) C
阿新 • • 發佈:2018-12-11
題意:
給你n個數,然後讓你刪掉一些數使得剩下的數的gcd比原來的gcd大,並且要使刪掉的數的數量最少
最後輸出需要刪掉的數的數量
解析:
大致有兩種做法,我用的是將每一個數質因數分解
這個分解用的是線性篩,因為線性篩中遍歷到每一個合數時都是通過該合數最小的質因數*某一個數
得到的,那麼我們就用mu[]記錄每一個數最小的質因數,然後遞迴地分解這個數就可以了
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 15000000+10; const int MAXN = 3e5+10; bool vis[N]; int mu[N]; int prime[MAXN*5],cnt; int a[MAXN]; int b[MAXN]; int num[N]; int maxx; int maxgcd; inline void solve() { //memset(mu,0,sizeof(mu)); cnt = 0; vis[0]=vis[1]=true; for(int i=2; i<N; i++) { if(!vis[i]) //vis用於標記是否是非素數,若是素數則為false { prime[cnt++] = i; //i=d } for(int j=0; j<cnt&&i*prime[j]<N; j++) { vis[i*prime[j]] = 1; if(i%prime[j]) mu[i*prime[j]] = prime[j]; //如果這個合數(暫且說成合數,質數的情況同理)不能被prime[j]整除,prime[j]肯定不是i的因子(換句話說i中沒有與prime[j]相同的因子) else //如果i%prime[j]==0那麼i肯定可以分解成prime[j]*(某一個數),這樣到之後k=i*prime[j+1]時,k肯定可以從prime[j+1]*(某一個數)*prime[j]得到(一個更大的合數*一個更小的質數得到你) { mu[i*prime[j]] = prime[j]; //如果這個合數(質數)能被prime[j]整除,那麼prime[j]就是i的因子,i*prime[j]中肯定有相同的質因子 break; //這樣相比與普通篩法O(n*logn*logn)就避免了重複,使得複雜度可以降到O(n) } } } } int gcd(int a,int b) { int k; while(b) { k=a%b; a=b; b=k; } return a; } bool tim[N]; inline void PollardRho(int n) { int flag=0; if(!vis[n]) { num[n]++; maxx=max(num[n],maxx); return; } int u=n; int tmp=mu[u]; while(vis[u]&&tmp) { if(!tim[tmp]) { num[tmp]++; maxx=max(num[tmp],maxx); tim[tmp]=true; } u=u/tmp; tmp=mu[u]; } if(!vis[u]&&!tim[u]) { num[u]++; maxx=max(num[u],maxx); } u=n; tmp=mu[u]; while(vis[u]&&tmp) { tim[tmp]=false; u=u/tmp; tmp=mu[u]; } } int main() { solve(); int n; scanf("%d",&n); scanf("%d",&a[1]); int mg=a[1]; for(int i=2;i<=n;i++) scanf("%d",&a[i]),mg=gcd(mg,a[i]); int flag=0; int cm=0,ans=0; for(int i=1;i<=n;i++) { a[i]=a[i]/mg; //if(a[i]!=1) flag=1; } maxx=0; for(int i=1;i<=n;i++) { if(a[i]==1) continue; PollardRho(a[i]); } if(maxx==0) printf("-1\n"); else printf("%d\n",n-maxx); return 0; }
另外一種我是看standing裡的一位大佬的程式碼,他是用類似普通篩法(nlogn)列舉每一個公約數的倍數
假如原來的最大公因數是d,那麼他從d+1開始列舉每一個數x,然後列舉x的倍數,看a裡面有多少數是x的倍數
然後把是x的倍數的數都刪掉,因為這些數已經被x替代了,因為一定是x的答案更優,
a裡面是x的倍數的數>=a裡面是k*x的倍數的數(k=1,2,3,4)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int INF =0x3f3f3f3f; const int MAXN =1.5e7 + 10; int pi[MAXN], a[MAXN]; int main() { int n, d = 0; scanf("%d",&n); for (int i=0; i<n; ++i) { int in; scanf("%d", &in); a[in]++; if (d==0) d = in; else d = __gcd(d,in); } int ans = n; for (int i=d + 1;i<MAXN; ++i) if (pi[i]==0) { int cnt = 0; for (int j = i; j < MAXN; j += i) pi[j] = 1, cnt += a[j]; ans = min(ans,n-cnt); } if (ans < n) printf("%d",ans); else printf("-1"); return 0; }