1. 程式人生 > >Enlarge GCD【Codeforces Round #511 (Div. 2)】【素數篩思想】

Enlarge GCD【Codeforces Round #511 (Div. 2)】【素數篩思想】

題目連結

思路

  這道題的思路取自素數篩,甚至是尤拉篩,我們要刪除一些數字,使得gcd增長,那麼,我們就得把除去公共gcd之後的數進行一次篩選,從最小的開始,我們求出那些個有相同質因數的數的數量的最大值。

舉個例子: 對於2 4 4 8 8  ; 他們的gcd==2, 除以2以後:1 2 2 4 4,我們從2開始遍歷“1~maxn”, 發現有4個是2的倍數,所以我們刪除的是N-4==1。

或許一個例子不夠形象: 對於3 6 6 9 ; 它們的gcd==3, 除以3以後:1 2 2 3,我們從2開始,2個是2的倍數, 1個是3的倍數,之後5、7、11......沒有這樣的數了,所以刪除N-2==2即可。

思路就是這樣的。

特殊的,對於除完之後只剩下“1,1,1,1,......”這樣的數,我們直接printf("-1\n")

完整程式碼:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=300005;
const int maxA=15000005;
int N, tree[maxN<<2], a[maxN], cnt[maxA];
bool vis[maxA];
int gcd(int a, int b)
{
    return b==0?a:gcd(b, a%b);
}
void buildTree(int rt, int l, int r)
{
    if(l==r)
    {
        scanf("%d", &a[l]);
        tree[rt]=a[l];
        return;
    }
    int mid=(l + r)>>1;
    buildTree(rt<<1, l, mid);
    buildTree(rt<<1|1, mid+1, r);
    tree[rt]=gcd(tree[rt<<1], tree[rt<<1|1]);
}
int main()
{
    while(scanf("%d", &N)!=EOF)
    {
        buildTree(1, 1, N);
        memset(cnt, 0, sizeof(cnt));
        int dislike=tree[1];
        int ans=0, sum=0;
        for(int i=1; i<=N; i++)
        {
            a[i]/=dislike;
            cnt[a[i]]++;
        }
        memset(vis, false, sizeof(vis));
        for(int i=2; i<maxA; i++)
        {
            if(!vis[i])
            {
                ans=0;
                for(int j=i; j<maxA; j+=i)
                {
                    ans+=cnt[j];
                    vis[j]=true;
                }
            }
            sum=max(sum, ans);
        }
        if(sum==0) printf("-1\n");
        else printf("%d\n", N-sum);
    }
    return 0;
}