bzoj-2082 Divine divisor

原创 2015年11月23日 13:29:57

题意:

给出一个数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;
}




版权声明:

相关文章推荐

BZOJ2082: [Poi2010]Divine divisor

题目大意:给出一个用m个ai乘起来表示的n,求出一个最大的k,使得存在一个d,使得d^k|n,并求出在这种情况下符合条件的d的个数 我们想求得答案,很自然的想要进行质因数分解,想要把n进行质因数分...

[BZOJ 2082]POI 2010 Divine divisor

数论小集合。 题目里第一问本质上要求的其实是 数a1*a2*a3*....*am(m2^(指数是k的素数个数)-1 瓶颈在于我们如何求出这个质因数分解,ai 我们最多能找出ai在10^6(不到8...

[BZOJ2082][Poi2010][质因数分解][乱搞]Divine divisor

题意找到最大k,使得若m为n的因数,则m^k也为n的因数,并求出有多少个m满足条件BZOJ300题留念(果然还是不够)在status里随手点开的题,因为要求最大的k,那么对于满足条件的n,不可能存在平...

BZOJ2082[POI2010] Divine divisor

BZOJ2082[POI2010] Divine divisor Description Tz耍畸形,在寂寞的时候玩一个游戏,他随便找出一个n,然后算出n的所有因子,最后...

Poi2010 Divine Divisor

Solution:首先我们想到吧所有的数质因子分解,所得到的每个质因子的个数的和的最大值就是要求的k,而我们设这个最大值出现的次数为m,则我们可以知道,任意个这样的质因子的乘积都是可行的一种解,所以第...

迭代与递归:To Iterate,Human; to Recurse, Divine.

引言 从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?「从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?『从前有座山,山里有座庙,...

smpte_2081_2082

  • 2016-03-22 09:34
  • 2.10MB
  • 下载

Calculate the Greatest Commom Divisor (GCD) and Lowest Common Multiple (LCP) of Two Integers

以上方法是用更相减损法求最大公约数,所谓更相减损法,即“以少减多,更相减损,求其等也,以等数约之,等数约之,即除也,其所以相减者皆等数之重叠,故以等数约之”。

【codeforces 762A】k-th divisor

time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandar...

Hdu 5207 Greatest Greatest Common Divisor(数论)

题目链接 Greatest Greatest Common Divisor Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)