Bzoj3837 [Pa2013]Filary(随机化)

题面

权限题

题解

这题有一个很好的性质,就是一定有$k>\frac n2$。接着考虑怎么做。

我们随机选取一个数$x$,然后将所有数与它作差,那么只需要找出$k$个差值使得他们的最大公因数大于$1$即可。我们可以将所有差值分解质因数,然后统计每个质因数出现的次数,再加上与$x$相等的数的个数就是$k$。统计$k$个时候顺便记录一下这些数的最大公因数即可。

根据之前说的那个性质,我们随机出真答案的期望是$log$的。但是随机化这个东西...是靠脸的,我最开始用了那个$8$位质数做种子,然后调了$10$次,最后调了半天改成不用种子,随机$4$次。

#include <cstdio>
#include <cstring>
#include <algorithm>
using std::min; using std::max;
using std::swap; using std::sort;
using std::__gcd;
typedef long long ll;

template<typename T>
void read(T &x) {
    int flag = 1; x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
    while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
}

const int N = 1e5 + 10, M = 1e7 + 10, _ = 1e6 + 10;
int n, x, nk, nm, k, m, tot;
int prime[_], save[M], s[_], g[_], v[N], c[N];
bool notprime[M];

int main () {
    for(int i = 2; i <= 10000000; ++i) {
        if(!notprime[i]) prime[++tot] = i, save[i] = tot;
        for(int j = 1; j <= tot && i * prime[j] <= 10000000; ++j) {
            notprime[i * prime[j]] = 1, save[i * prime[j]] = j;
            if(!(i % prime[j])) break;
        }
    } read(n);
    for(int i = 1; i <= n; ++i) read(v[i]);
    for(int T = 1; T <= 4; ++T) {
        x = v[rand() % n + 1], nk = s[0] = 0;
        for(int i = 1; i <= n; ++i) {
            c[i] = abs(v[i] - x);
            if(!c[i]) ++s[0];
        }
        for(int i = 1; i <= n; ++i) {
            int t = c[i];
            while(t && t != 1) {
                int tmp = save[t];
                ++s[tmp], g[tmp] = __gcd(g[tmp], c[i]);
                if(nk < s[tmp] + s[0]) nk = s[tmp] + s[0], nm = 0;
                if(nk == s[tmp] + s[0]) nm = max(nm, g[tmp]);
                while(!(t % prime[tmp])) t /= prime[tmp];
            }
        }
        
        if(nk > k) k = nk, m = 0;
        if(nk == k) m = max(m, nm);
        for(int i = 1; i <= n; ++i) {
            int t = c[i];
            while(t && t != 1) {
                int tmp = save[t];
                s[tmp] = g[tmp] = 0;
                while(!(t % prime[tmp])) t /= prime[tmp];
            }
        } 
    }printf("%d %d\n", k, m);
    return 0;
} 

 

posted @ 2019-01-10 07:41  water_mi  阅读(293)  评论(0编辑  收藏  举报