[PA2013] Filary

链接

\(m = 2\),可以得到答案的一个下界是 \(\lceil {n \over 2} \rceil\)

直接做很难处理,考虑随机一个值必选。根据答案下界,随机一次能得到最优解的概率大于 \(1 \over 2\),因此随机 \(20\) 次左右即可。

同余条件即 \(m \mid x - y\)\(x\) 已经通过随机固定,那么枚举每个数 \(y\),将 \(x - y\) 的所有 素因子 用桶维护,取最大值。

但可能存在合数 \(m\),使 \(k\) 同样可以取到最大,可以考虑将两个对应 \(a_i\) 的位置完全相同 的素因子 “合并”。

如果暴力维护,那么单次尝试 \(\mathcal O(n \log^2 n)\),因为合法的素因子只有 \(\mathcal O(\log n)\) 个,我们可以考虑给每 \(a_i\) 赋随机权值,对每个素因子维护 xor-Hash 即可。

线性筛出每个数最小素因子,复杂度 \(\mathcal O(V + T\cdot n \log n)\)\(T\) 为随机次数。

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
#include <random>
#include <chrono>
using namespace std;
using ll = long long;
using u64 = unsigned long long;

namespace io {
#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
  const int SIZE = (1 << 21) + 1;
  char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1;
  inline char getc () {return (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++);}
  inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
  inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
  template<class T>
  inline void read(T &x) {
    char ch; int f = 1;
    x = 0;
    while(isspace(ch = getc()));
    if(ch == '-') ch = getc(), f = -1;
    do x = x * 10 + ch - '0'; while(isdigit(ch = getc()));
    x *= f;
  }
  template<class T, class ...Args>
  inline void read(T &x, Args&... args) {read(x); read(args...);}
  template<class T>
  inline void write(T x) {
    static char stk[128];
    int top = 0;
    if(x == 0) {putc('0'); return;}
    if(x < 0) putc('-'), x = -x;
    while(x) stk[top++] = x % 10, x /= 10;
    while(top) putc(stk[--top] + '0');
  }
  template<class T, class ...Args>
  inline void write(T x, Args... args) {write(x); putc(' '); write(args...);}
  inline void space() {putc(' ');}
  inline void endl() {putc('\n');}
  struct _flush {~_flush() {flush();}} __flush;
};
using io::read; using io::write; using io::flush; using io::space; using io::endl; using io::getc; using io::putc;

mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());

const int V = 10000004, P = 664600, N = 1000005;
bool np[V];
int p[P], pc = 0, lpf[V];

void prime_sieve(int n) {
  for (int i = 2; i <= n; ++i) {
    if (!np[i])
      p[++pc] = i, lpf[i] = pc;
    for (int j = 1; j <= pc && i * p[j] <= n; ++j) {
      np[i * p[j]] = true;
      lpf[i * p[j]] = j;
      if (i % p[j] == 0) break;
    }
  }
}

int k = 0, m = -1;
int cnt[N], val[N], minexp[N], cv = 0;
u64 id[N], Hash[P];
int occ[P];
void work(int select) {
  fill(Hash + 1, Hash + 1 + pc, 0);
  fill(occ + 1, occ + 1 + pc, 0);
  fill(minexp, minexp + 1 + pc, numeric_limits<int>::max());
  int nowc = 0;
  for (int i = 1; i <= cv; ++i) {
    if (val[i] == select) {
      nowc = cnt[i];
      continue;
    }
    int x = abs(val[i] - select);
    int last = 0, ex = 0;
    while (x != 1) {
      if (lpf[x] != last) {
        occ[lpf[x]] += cnt[i];
        if (last) minexp[last] = min(minexp[last], ex);
        ex = 1;
        Hash[lpf[x]] ^= id[i];
        last = lpf[x];
      }
      else ++ex;
      x /= p[lpf[x]];
    }
    if (last) minexp[last] = min(minexp[last], ex);
  }
  int K = *max_element(occ + 1, occ + 1 + pc), M = 0, fc = 0;
  static int fac[128], prod[128];
  if (K + nowc < k) return;

  for (int i = 1; i <= pc; ++i)
    if (occ[i] == K) fac[++fc] = i;
  for (int i = 1; i <= fc; ++i) {
    prod[i] = 1;
    for (int t = minexp[fac[i]]; t; --t) prod[i] *= p[fac[i]];
    for (int j = 1; j < i; ++j)
      if (Hash[fac[i]] == Hash[fac[j]]) {
        prod[j] *= prod[i];
        break;
      }
    }
  K += nowc;
  M = *max_element(prod + 1, prod + 1 + fc);
  if (K > k) m = M, k = K;
  else if (K == k && M > m) m = M;
}

int a[N];

int main() {
  prime_sieve(10000000);
  int n, cmod2[2] = {0, 0};
  read(n);
  m = 2;
  for (int i = 1; i <= n; ++i)
    read(a[i]), ++cmod2[a[i] & 1];
  k = max(cmod2[0], cmod2[1]);

  sort(a + 1, a + 1 + n);
  for (int i = 1; i <= n; ++i) {
    if (a[i] != a[i - 1]) {
      ++cv;
      val[cv] = a[i]; cnt[cv] = 1;
      id[cv] = rnd();
    }
    else ++cnt[cv];
  }
  uniform_int_distribution<int> D(1, n);
  for (int T = 1; T <= 20; ++T) {
    int p = D(rnd);
    work(a[p]);
  }
  write(k, m), endl();
  return 0;
}
posted @ 2020-09-19 23:24  RiverHamster  阅读(412)  评论(0编辑  收藏  举报
\