簡要題意:
給你一個長度爲 的查詢序列,請你選擇一個哈希表長,最大化查詢總用時,哈希表實現和用時計算方式參考如下(不考慮空間開不下的情況):
// h is the hash table.
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;
}
數據範圍:
題解:
首先直覺明白並不能直接計算,應該是考慮一些可能,然後計算後取最大值。
首先這道題關鍵的一點,什麼樣的數值得考慮。有一個顯然的條件,存在,使得 ,如果不滿足顯然根本不用考慮,答案肯定是。
所以可以直接分解因數,用Pollard-Rho即可。
衆所周知 以下的數,因子數最多可以達到 級別。
不能考慮所有因子。
注意到 能做出的貢獻一定不小於 ,這很顯然,這啓示我們對選擇範圍進行簡化。
但是由於要求是,所以有的質數不一定能選用,考慮這些質因數在中的數就行了。
計算的話可以直接用哈希表模擬,反正這部分複雜度很小。
代碼:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
std::mt19937 R(time(0));
namespace Sieves{
bool mrk[400007];
int minp[400007];
int pr[400007],pct;
void linear_sieves(int lim=4e5){
for(int i=2;i<=lim;++i){
if(!mrk[i])pr[++pct]=i,minp[i]=i;
for(int re j=1;i*pr[j]<=lim;++j){
mrk[i*pr[j]]=true;minp[i*pr[j]]=pr[j];
if(i%pr[j]==0)break;
}
}
}
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll mul(ll a,ll b,ll mod){return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;}
inline ll power(ll a,ll b,ll mod){ll res=1;a%=mod;
for(;b;b>>=1,a=mul(a,a,mod))(b&1)&&(res=mul(res,a,mod));return res;}
inline bool isprime(ll x){
static cs int p[17]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59};
ll t=x-1,s=0;
while(!(t&1))t>>=1,++s;
for(int re tim=0;tim<=5;++tim){
ll a=p[rand()%17];
ll b=power(a,t,x);
for(int re j=1;j<=s;++j){
ll k=mul(b,b,x);
if(k==1&&b!=1&&b!=x-1)return false;
b=k;
}
if(b!=1)return false;
}
return true;
}
inline ll Rho(ll p){
if(p%2==0)return 2;
ll c=(ll)R()%(p-1)+2,x=1,m=1,t;
for(int re k=2;;k<<=1){
ll q=1;
for(int re s=1;s<=k;++s){
x=mul(x,x,p)+c;if(x>=p)x-=p;
q=mul((x-m+p)%p,q,p);
if(!(s&127)&&(t=gcd(p,q))!=1)return t;
}
if((t=gcd(q,p))!=1)return t;
m=x;
}
}
}
cs int magic=1887579;
struct Map{
ll key[magic];Map(){memset(key,-1,sizeof key);}
bool find(ll k)cs{
int h=k%magic;
while(key[h]!=-1&&key[h]!=k)h=(h+1)%magic;
return key[h]==k;
}
void insert(ll k){
int h=k%magic;
while(key[h]!=-1&&key[h]!=k)h=(h+1)%magic;
key[h]=k;
}
}sieved;
std::vector<ll> pfac;int n;
inline void get_factor(ll x){
using namespace Sieves;
if(x==1||sieved.find(x))return ;
sieved.insert(x);
if(isprime(x)){pfac.push_back(x);return ;}
ll p=Rho(x);get_factor(p);get_factor(x/p);
}
inline void factor(ll x){
using namespace Sieves;
for(int i=1;i<=200;++i)while(x%pr[i]==0)x/=pr[i];
get_factor(x);
}
ll a[209];
ll key[magic],key2[magic];
int st[209],tp;
inline int locate(ll k){
int h=k%magic;
while(key[h]!=-1&&key[h]!=k)h=h==magic-1?0:h+1;
return h;
}
int solve(ll len){
int ans=0;
for(int re i=1;i<=n;++i){
for(ll x=a[i]%len;;x=x==len-1?0:x+1,++ans){
int h=locate(x);
if(key[h]==-1){
st[++tp]=h;
key[h]=x;
key2[h]=a[i];
break;
}if(key2[h]==a[i])break;
}
}
while(tp)key[st[tp--]]=-1;
return ans;
}
void Main(){
scanf("%*d%d",&n);
Sieves::linear_sieves();
for(int re i=1;i<=n;++i)
scanf("%lld",a+i);
for(int re i=1;i<=n;++i)
for(int re j=i+1;j<=n;++j)
if(a[i]!=a[j]){
ll x=a[i]-a[j];
if(x<0)x=-x;factor(x);
}
memset(key,-1,sizeof key);
int res=0;for(int re i=n;i<=n*n;++i)if(i/Sieves::minp[i]<=n)res=std::max(res,solve(i));
for(ll v:pfac)res=std::max(res,solve(v));cout<<res<<"\n";
}
inline void file(){
#ifdef zxyoi
freopen("hash.in","r",stdin);
#endif
}
signed main(){file();Main();return 0;}