【BZOJ3837】[PA2013]Filary

【BZOJ3837】[PA2013]Filary

题面

darkbzoj

题解

考虑到模数为\(2\)时答案至少为\(\frac n2\),这是我们答案的下界。

那么我们对于任意的一个数,它们答案集合中的就概率至少为\(\frac 12\)

那么我们随机选出一个数,将这个数与其他数作差,那么将这些数分解质因数后出现次数最多的数的个数就是出现次数,而含有这个质因数的所有数的\(gcd\)就是这种情况。

因为值域\(\leq 10^7\),所以你把每个数最小的质因子筛出来就可以做到\(\log\)的分解质因数了,注意特判差为零的情况。

如果你不是太非随机十次左右就够了。

代码

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <cmath> 
#include <algorithm>
#include <ctime> 
using namespace std; 
inline int gi() { 
    register int data = 0, w = 1; 
    register char ch = 0; 
    while (!isdigit(ch) && ch != '-') ch = getchar(); 
    if (ch == '-') w = -1, ch = getchar(); 
    while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar(); 
    return w * data; 
} 
const int MAX_N = 1e5 + 5; 
const int MAX_V = 1e7 + 5, MAX = 1e7; 
int prime[700000], minp[MAX_V], num; 
void sieve() { 
    for (int i = 2; i <= MAX; i++) { 
        if (!minp[i]) prime[++num] = i, minp[i] = i; 
        for (int j = 1; j <= num && i * prime[j] <= MAX; j++) { 
            minp[i * prime[j]] = prime[j]; 
            if (i % prime[j] == 0) break; 
        } 
    } 
} 
int N, a[MAX_N], Cnt[MAX_V], Gcd[MAX_V]; 
pair<int, int> ans; 

int main () { 
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif 
    srand(time(NULL)); 
    sieve(); 
    N = gi(); 
    for (int i = 1; i <= N; i++) a[i] = gi(); 
    for (int i = 1; i <= N; i++) if (a[i] & 1) ans.first++; 
    ans.first = max(ans.first, N - ans.first), ans.second = 2; 
    for (int T = 10; T--; ) { 
        int pos = rand() % N + 1, ALL = 0; 
        for (int i = 1; i <= N; i++) { 
            int dlt = abs(a[pos] - a[i]), tmp = dlt; 
            if (!dlt) ++ALL;
            else { 
                int lst = 0; 
                while (tmp != 1) { 
                    if (minp[tmp] != lst) { 
                        Cnt[minp[tmp]]++; 
                        Gcd[minp[tmp]] = __gcd(dlt, Gcd[minp[tmp]]); 
                    } 
                    lst = minp[tmp], tmp /= minp[tmp]; 
                } 
            } 
        }
        for (int i = 1; i <= N; i++) { 
            int dlt = abs(a[pos] - a[i]), tmp = dlt; 
            if (!dlt) continue; 
            else { 
                int lst = 0; 
                while (tmp != 1) { 
                    if (minp[tmp] != lst) { 
                        ans = max(ans, make_pair(ALL + Cnt[minp[tmp]], Gcd[minp[tmp]])); 
                        Cnt[minp[tmp]] = 0; 
                        Gcd[minp[tmp]] = 0; 
                    } 
                    lst = minp[tmp], tmp /= minp[tmp]; 
                } 
            } 
        } 
    } 
    printf("%d %d\n", ans.first, ans.second); 
    return 0; 
} 
posted @ 2019-10-30 15:38  heyujun  阅读(...)  评论(... 编辑 收藏