【校內模擬】魚貫而入(Pollard-Rho)

簡要題意:

給你一個長度爲 nn 的查詢序列,請你選擇一個哈希表長,最大化查詢總用時,哈希表實現和用時計算方式參考如下(不考慮空間開不下的情況):

// 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;
}

數據範圍:n200,ai1e18n\leq 200, a_i\leq 1e18


題解:

首先直覺明白並不能直接計算,應該是考慮一些可能lenlen,然後計算後取最大值。

首先這道題關鍵的一點,什麼樣的數值得考慮。有一個顯然的條件,存在i,ji,j,使得 lenaiajlen \mid |a_i-a_j|,如果不滿足顯然根本不用考慮,答案肯定是00

所以可以直接分解因數,用Pollard-Rho即可。

衆所周知 1e181e18 以下的數,因子數最多可以達到 1e51e5 級別。

不能考慮所有因子。

注意到 pp 能做出的貢獻一定不小於 kpkp ,這很顯然,這啓示我們對選擇範圍進行簡化。

但是由於要求是lennlen\geq n,所以有的質數不一定能選用,考慮這些質因數在[n.nn][n.n*n]中的數就行了。

計算的話可以直接用哈希表模擬,反正這部分複雜度很小。


代碼:

#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;} 
發佈了993 篇原創文章 · 獲贊 374 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章