题意:寻找一个模数使得一组数的 寻址时间最长, ,其中寻址代码如下
void add_fish(long long &cnt, long long x, long long len) {
long long y = x % len;
while(h[y] != -1 && h[y] != x)
y = (y + 1) % len, cnt ++;
h[y] = x;
}
long long solve(long long len) {
for(int i = 0; i < len; i ++) h[i] = -1;
long long cnt = 0;
for(int i = 1; i <= n; i ++) add_fish(cnt, a[i], len);
return cnt;
}
- 题解
直接算显然没法算,考虑找几个较优的 然后逐一计算比较
一个显而易见的条件是 ,否则寻址时间一定为 0
于是就有了我们的做法,枚举每一对 ,找到所有的约数,再进行判断,判断可以用并查集做到近似 ,那么我们的复杂度就是 后面的为分解复杂度
考虑 的时候,分解可以用 ,需要优化前面的复杂度
发现如果一个数 可行,那么 均没有 优
于是我们需要判断的仅有 的哪些
这些数分为两类,一类是 的合数及质数,一类是 的质数
第二个用 分解出来,然后把 的所有数 一遍
这样子复杂度是
然后并不用并查集,严重卡不满, 模拟即可
先弱化条件,找到一群较优的来判断比较巧妙
#include<bits/stdc++.h>
#define cs const
using namespace std;
typedef long long ll;
ll read(){
ll cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 205, K = 1e6 + 50;
int n; ll a[N];
int prim[K], minp[K], pc; bool isp[K];
vector<ll> fac, S;
ll rnd(){ return rand()|((ll)rand()<<15)|((ll)rand()<<30)|((ll)rand()<<45); }
ll mul(ll x, ll y, ll mod){ return (ll)(x * y - (ll)((long double)x / mod * y) * mod + mod) % mod; }
ll ksm(ll a, ll b, ll mod){ ll ans = 1; for(;b;b>>=1,a=mul(a,a,mod)) if(b&1) ans=mul(ans,a,mod); return ans; }
ll gcd(ll a, ll b){ return !b ? a : gcd(b, a % b); }
void linear_sieve(int n){
for(int i = 2; i <= n; i++){
if(!isp[i]) minp[i] = i, prim[++pc] = i;
for(int j = 1; j <= pc; j++){
if(i * prim[j] > n) break;
isp[i * prim[j]] = true;
minp[i * prim[j]] = prim[j];
if(i % prim[j] == 0) break;
}
}
}
bool miller(ll x){
if(x <= K - 50) return !isp[x];
static int c[17] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51,53};
ll t = x-1, y = 0;
while(t&1^1) t>>=1, ++y;
for(int i = 0; i < 5; i++){
ll p = c[rand() % 17], now = ksm(p, t, x);
for(int j = 1; j <= y; j++){
ll nxt = mul(now, now, x);
if(nxt == 1 && now != 1 && now != x-1) return false;
now = nxt;
} if(now != 1) return false;
} return true;
}
ll Rho(ll x){
ll c = (ll)rnd() % (x-1) + 1, nxt = 1, now = 0;
for(int k = 2; ; k <<= 1){
ll prod = 1;
for(int i = 1; i <= k; i++){
nxt = mul(nxt, nxt, x) + c; if(nxt >= x) nxt -= x;
prod = mul(prod, abs(nxt-now), x);
}
ll g = gcd(prod, x); if(g > 1) return g;
now = nxt;
}
}
void Factor(ll x){
if(x == 1) return;
if(miller(x)){ fac.push_back(x); return; }
ll now = Rho(x);
while(x % now == 0) x /= now;
Factor(now); Factor(x);
}
void Solve(ll x){
for(int i = 1; i <= 200; i++) if(x % prim[i] == 0){
fac.push_back(prim[i]);
while(x % prim[i] == 0) x /= prim[i];
} Factor(x);
}
int ans, sta[N], top;
cs int P = 19260817;
ll key[P+1], vl[P+1];
int locate(ll x){
int ps = x % P;
while(key[ps] != -1 && key[ps] != x) ps = ps == P-1 ? 0 : ps+1;
return ps;
}
void calc(ll len){
int ct = 0;
for(int i = 1; i <= n; i++){
for(ll x = a[i] % len; ; x = x == len-1 ? 0 : x+1, ++ct){
int p = locate(x);
if(key[p] == -1){
sta[++top] = p;
key[p] = x; vl[p] = a[i];
break;
} if(vl[p] == a[i]) break;
}
}
while(top) key[sta[top--]] = -1;
ans = max(ans, ct);
}
int main(){
srand(time(0));
linear_sieve(K - 50);
read();
n = read();
for(int i = 1; i <= n; i++) a[i] = read();
for(int i = 1; i <= n; i++)
for(int j = i+1; j <= n; j++) if(a[i] ^ a[j]){
ll x = a[i] - a[j]; if(x < 0) x = -x;
fac.clear(); Solve(x);
for(ll x : fac) if(x >= n * n) S.push_back(x);
}
memset(key, -1, sizeof(key));
for(int i = n; i <= n * n; i++) if(i / minp[i] < n) calc(i);
for(ll x : S) calc(x);
cout << ans;
return 0;
}