zoukankan      html  css  js  c++  java
  • 6468. 【GDOI2020模拟02.09】鱼贯而入

    题目

    正解

    比赛时几乎没有怎么思路。
    其实这个东西应该很显然:如果要让答案大于$0¥,那么至少存在两个会有冲突,也就是说在模了之后至少有两个不同的数的位置会重叠。
    所以只需要枚举两两之间的差的约数,都试一遍就可以了。

    这样当然会TLE。
    考虑某个数(p)以及它的倍数(kp),显然,在(kp)中撞上的在(p)中一定也能撞上,所以如果(p)符合条件,就不用算(kp)了。
    所以,对于某个数(x),求出它的最小质因子(y),只有(frac{x}{y}<n)的时候才有必要计算(x)
    按照这个性质,可以进一步推出:要么(x)是素数,否则(xin [n,n^2])

    对于([n,n^2])的每个都枚举一遍,借助并查集用接近(O(n))的时间计算。
    对于大质数,用Polllard-Rho方法分解出来之后计算,计算的时候与前面的类似,不过还要打个哈希表来模拟下标。


    代码

    其实这题说起来容易,但代码实现起来真的有点恶心。
    话说Pollard-Rho有个不错的优化,就是不要每次枚举都计算(gcd),乘(128)个之后再求(gcd)
    为了防止圈过小的情况,还要倍增一下。

    然后就是我终于知道了原来long long相乘取模借助long double可以做到几乎没有误差。最重要的是要在相乘之前先让它们对模数取模。

    还有,经过实测,x*x+c的伪随机方式似乎带着一种奇怪的魔力。用其它的方法进行伪随机时间会T飞。

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <cstdlib>
    #include <ctime>
    #define N 210
    #define ll long long
    #define ull unsigned long long
    int n;
    long long a[N];
    int lst[N];
    ull ans;
    ll mul(ll x, ll y, ll mo) {
        ll z = (long double) x * y / mo;
    	z = x * y - z * mo;
        if(z < 0) z += mo; else if(z > mo) z -= mo;
        return z;
    }
    inline ull qpow(ull x,ull y,ull mo){
    	ull res=1;
    	for (;y;y>>=1,x=mul(x,x,mo))
    		if (y&1)
    			res=mul(res,x,mo);
    	return res;
    }
    const int p[9]={2,3,5,7,11,13,17,19,23};
    inline bool mr(ull v){
    	if (v==0 || v==1)
    		return 0;
    	for (int i=0;i<9;++i){
    		if (v==p[i])
    			return 1;
    		if (v%p[i]==0)
    			return 0;
    	}
    	ull x=v-1,k=0;
    	while (!(x&1))
    		x>>=1,++k;
    	for (int i=0;i<9;++i){
    		ull t=qpow(p[i],x,v);
    		if (t==1 || t==v-1)
    			continue;
    		for (int j=1;j<k;++j){
    			t=mul(t,t,v);
    			if (t==v-1)
    				break;
    		}
    		if (t!=v-1)
    			return 0;
    	}
    	return 1;
    }
    inline ull gcd(ull a,ull b){
    	while (b){
    		ull k=a%b;
    		a=b,b=k;
    	}
    	return a;
    }
    #define irand (rand()*RAND_MAX+rand())
    #define lrand (irand*RAND_MAX*RAND_MAX+irand)
    inline ull rho(ull n){
    	while (1){
    		ull a=lrand%n,c=lrand%n,k=lrand%n,b=a,s=1;
    		for (int i=1,k=2;1;++i){
    			a=(a*a+c)%n;
    //			printf("%llu %llu
    ",a,abs((long long)a-(long long)b)); 
    			if (a==b)
    				break;
    			ull t=mul(s,abs((long long)a-(long long)b),n);
    			if (t==0)
    				return gcd(s,n);
    			s=t;
    			if (i==k){
    				ull g=gcd(s,n);
    				if (g!=1)
    					return g;
    				k<<=1;
    				b=a;
    				continue;
    			}
    			if (!(i&127)){
    				ull g=gcd(s,n);
    				if (g!=1)
    					return g;
    			}
    		}
    	}
    }
    #define SIZE 40010
    int fa[SIZE],need[N];
    int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
    inline ull calc1(int len){
    	for (int i=0;i<len;++i)
    		fa[i]=i;
    	ull res=0;
    	for (int i=1;i<=n;++i){
    		if (lst[i]){
    			res+=need[i]=need[lst[i]];
    			continue;
    		}
    		int x=a[i]%len;
    		getfa(x);
    		res+=need[i]=(fa[x]>=x?fa[x]-x:len+fa[x]-x);
    		x=fa[x];
    		int y=getfa((x+1)%len);
    		fa[x]=y;
    	}
    	return res;
    }
    #define mo 3001 
    ull id[mo],used[N][2];
    inline int myhash(ull key){
    	int i=key%mo;
    	for (;id[i] && id[i]!=key;i=(i+1==mo?0:i+1));
    	return i;
    }
    inline int newnode(ull key){
    	int i=myhash(key);
    	if (id[i]==0){
    		id[i]=key;
    		fa[i]=i;
    	}
    	return i;
    }
    inline ull calc2(ull len){
    	ull res=0;
    	for (int i=1;i<=n;++i){
    		if (lst[i]){
    			res+=need[i]=need[lst[i]];
    			continue;
    		}
    		ull x=a[i]%len,ha=myhash(x);
    		if (id[ha]==0){
    			id[ha]=x;
    			fa[ha]=newnode((x+1)%len);
    			used[i][0]=ha;
    			used[i][1]=fa[ha];
    			need[i]=0;
    			continue;
    		}
    		getfa(ha);
    		res+=need[i]=(id[fa[ha]]>=x?id[fa[ha]]-x:len+id[fa[ha]]-x);
    		ha=fa[ha];
    		x=id[ha];
    		int y=getfa(newnode((x+1)%len));
    		fa[ha]=y;
    		used[i][0]=ha;
    		used[i][1]=y;
    	}
    	for (int i=1;i<=n;++i)
    		if (!lst[i])
    			id[used[i][0]]=id[used[i][1]]=0;
    	return res;
    }
    set<ull> vis;
    void find(ull v){
    	if (v<=n*n)
    		return;
    	if (vis.find(v)!=vis.end())
    		return;
    	vis.insert(v);
    	if (mr(v)){
    		ans=max(ans,calc2(v));
    		return;
    	}
    	ull d=rho(v);
    	ull u=v/d,g=gcd(d,u);
    	if (g!=1){
    		d/=g,u/=g;
    		find(g);
    	}
    	find(d),find(u);
    }
    int main(){
    	freopen("hash.in","r",stdin);
    	freopen("hash.out","w",stdout);
    	srand(time(0));
    	int type;
    	scanf("%d%d",&type,&n);
    	for (int i=1;i<=n;++i){
    		scanf("%lld",&a[i]);
    		for (int j=i-1;j>=0;--j)
    			if (a[i]==a[j]){
    				lst[i]=j;
    				break;
    			}
    	}
    	for (int i=n;i<=n*n;++i)
    		ans=max(ans,calc1(i));
    	for (int i=0;i<9;++i)
    		if (p[i]>n*n)
    			ans=max(ans,calc1(p[i]));
    	for (int i=1;i<=n;++i)
    		for (int j=i+1;j<=n;++j){
    			ull tmp=abs(a[i]-a[j]);
    			if (tmp==0)
    				continue;
    			for (int k=0;k<9;++k)
    				while (tmp%p[k]==0)
    					tmp/=p[k];
    			find(tmp);
    		}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    总结

    真是一个恶心的程序……
    不过,这也让我了解怎么更加优美地打Pollard-Rho。

  • 相关阅读:
    iOS开发之JSONKit
    iOS开发之XMPPFramework环境搭建和配置
    iOS开发之UICollectionViewController
    iOS开发之UITableViewController重写
    Object-c 开发之property
    Git使用
    解决CocoaPods下载慢的问题
    解决Linux下编译adb和fastboot问题
    解决fastboot刷机内存消耗问题
    sql
  • 原文地址:https://www.cnblogs.com/jz-597/p/12300531.html
Copyright © 2011-2022 走看看