bzoj-2082 Divine divisor

题意:

给出一个数N,求它最大的因子次数,以及有多少个这样的因子;

这个数很大,由不超过600个小于等于10^18的数给出;


题解:

首先对这个数进行质因数分解之后,最大的质因子次数就是第一问的答案;

第二问的答案就是最大质因子次数的质因子种类数的二的幂次-1;

这两步都是显然的,然而都是很坑的地方。。

第二问的幂次要用一个高精度加法,这个注意到就没什么了;

第一问的质因数分解如果裸分解的话,时间复杂度O(600*10^9)必然是跪的;

然而实际上,就算是MR+Rho算法也卡不过去几个点;

所以这道题一定还有一些奇怪的性质;

注意到我们可以预处理10^6次以下的质数,然后对其进行一个处理,除掉所有的10^6以下的因子;

那么此时这个数不可能有多于两个因子;

再用MR判断它是否是一个质数,这样处理之后被留下的数就一定是两个大质数相乘的形式;

再对每个数开根尝试分解这个数,排除掉p^2的形式;

因为我们实际上只关心每个质数出现了多少次,而不关心它是什么,所以我们将所有的数两两求GCD,求出GCD的就可以找到一个质因子了;

如果有剩下仍未分解的数,那么我们也将不需要分解它了,任意找两个偶数把它的两个因此扔进去计数就可以了,注意有数字相同的情况;

对质数的计数我用了hash表实现,最后只要扫一遍所有的链表就可以了;


代码:


</pre><pre name="code" class="cpp">#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 1500
#define PRE 1100000
using namespace std;
typedef long long ll;
struct HashSet
{
	#define mod 1401421
	int next[mod],val[mod],head[mod],ce;
	ll X[mod];
	int &operator [](ll x)
	{
		int index=x%mod;
		for(int i=head[index];i;i=next[i])
		{
			if(X[i]==x)
				return val[i];
		}
		X[++ce]=x;
		next[ce]=head[index];
		head[index]=ce;
		return val[ce];
	}
	#undef mod
}hash;
int pri[PRE],tot;
bool vis[PRE];
ll st[N],cov[N],siz[N],dis[N],top,len;
void init()
{
	int i,j;
	for(i=2;i<PRE;i++)
	{
		if(!vis[i])
			pri[++tot]=i;
		for(j=1;j<=tot&&pri[j]*i<PRE;j++)
		{
			vis[pri[j]*i]=1;
			if(i%pri[j]==0)
				break;
		}
	}
}
ll mul(ll x,ll y,ll mod)
{
	if(x<y)	swap(x,y);
	ll ret=0;
	while(y)
	{
		if(y&1)
		{
			ret+=x;
			if(ret>=mod)
				ret-=mod;
		}
		x+=x;
		if(x>=mod)
			x-=mod;
		y>>=1;
	}
	return ret;
}
ll pow(ll x,ll y,ll mod)
{
	ll ret=1;
	while(y)
	{
		if(y&1)
			ret=mul(ret,x,mod);
		x=mul(x,x,mod);
		y>>=1;
	}
	return ret;
}
bool check(ll u,ll t,ll now)
{
	ll s=rand()%(now-2)+2;
	s=pow(s,u,now);
	if(s==1||s==now-1)	return 1;
	for(ll i=1;i<=t;i++)
	{
		s=mul(s,s,now);
		if(s==now-1)	return 1;
	}
	return 0;
}
bool judge(ll now)
{
	if(now<2)	return 0;
	if(!(now&1))return now==2;
	ll u=now-1,t=0;
	while(!(u&1))
		u>>=1,t++;
	for(int c=1;c<=10;c++)
	{
		if(!check(u,t,now))
			return 0;
	}
	return 1;
}
void out(int cnt)
{
	ll M=1000000000;
	static ll a[N],len;
	a[1]=1;
	len=1;
	for(int i=1;i<=cnt;i++)
	{
		for(int j=1;j<=len;j++)
		{
			a[j]<<=1;
		}
		for(int j=1;j<=len;j++)
		{
			a[j+1]+=a[j]/M;
			a[j]%=M;
		}
		if(a[len+1])
			len++;
	}
	a[1]--;
	printf("%lld",a[len]);
	for(int j=len-1;j>=1;j--)
	{
		printf("%09lld",a[j]);
	}
	puts("");
}
int main()
{
	srand(140142);
	int n,m,i,j,k,x,y,ans,cnt;
	ll now,temp;
	init();
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
		scanf("%lld",&now);
		for(j=1;j<=tot;j++)
		{
			while(now%pri[j]==0)
				hash[pri[j]]++,now/=pri[j];
		}
		if(now==1)	continue;
		temp=sqrt(now)+0.1;
		if(temp*temp==now)
			hash[temp]+=2;
		else if(judge(now))
			hash[now]++;
		else
			st[++top]=now;
	}
	sort(st+1,st+top+1);
	memcpy(dis+1,st+1,sizeof(ll)*top);
	len=unique(dis+1,dis+top+1)-dis-1;
	for(i=1;i<=top;i++)
	{
		siz[lower_bound(dis+1,dis+len+1,st[i])-dis]++;
	}
	top=len;
	for(i=1;i<=top;i++)
		st[i]=dis[i];
	for(i=1;i<=top;i++)
	{
		for(j=i+1;j<=top;j++)
			if(i!=j&&(temp=__gcd(st[i],st[j]))!=1)
			{
				if(temp!=st[i])
					cov[i]=cov[j]=temp;
			}
		for(j=1;j<=hash.ce;j++)
		{
			if(st[i]%hash.X[j]==0)
			cov[i]=hash.X[j];
		}
	}
	for(i=1;i<=top;i++)
	{
		if(cov[i])
			hash[cov[i]]+=siz[i],hash[st[i]/cov[i]]+=siz[i];
		else
			hash[i<<2]+=siz[i],hash[i<<2|2]+=siz[i];
	}
	ans=0;
	for(i=1;i<=hash.ce;i++)
	{
		if(hash.val[i]>ans)
		{
			ans=hash.val[i];
			cnt=1;
		}
		else if(hash.val[i]==ans)
		{
			cnt++;
		}
	}
	printf("%d\n",ans);
	out(cnt);
	return 0;
}




你可能感兴趣的:(poi,数论,mr,hash表,bzoj)