首页 > 代码库 > HDU 3641 Treasure Hunting (二分+分解质因子)

HDU 3641 Treasure Hunting (二分+分解质因子)

题目链接:HDU 3641 Treasure Hunting

题意:求X!%M==0中最小的的X。其中M=a1^b1*a2^b2*a3^b3....

思路:求余为0想到整除,即分母的因子构成的集合是分子的因子构成的集合的子集。因子又想到,任何一个整数都可以分解成若干个素数相乘。

注意:题目数据很大,查到答案时二分。


AC代码:


#include<stdio.h>
#include<string.h>
#define ll __int64
bool Prime[210];
ll num[210];//M中的质因数个数

void getPrime()//素数打表
{
	int i,j;
	memset(Prime,true,sizeof Prime);
	Prime[0]=Prime[1]=false;
	for(i=2;i*i<=110;i++)
	{
		if(Prime[i])
		{
			for(j=i+i;j<=110;j+=i)
				Prime[j]=false;
		}
	}
}
void cal(ll a,ll b)//分解质因子
{
	ll i,n=a;
	for(i=2;i<=a;)
	{
		if(n%i==0 && Prime[i])
		{
			n/=i;
			num[i]+=b;
		}
		else
			i++;
	}
}
ll find(ll i,ll x) //x!中i的个数
{
	ll ans=0;
	while(x)
	{
		x/=i;
		ans+=x;
	}
	return ans;
}
bool ok(ll x)//
{
	ll i;
	for(i=1;i<=100;i++)
	{
		if(num[i])
		{
			ll temp=find(i,x);
			if(num[i]>temp) //分母的质因子个数比分子质因子大。
				return false;
		}
	}
	return true;
}
ll bfind()//二分查到答案
{
	ll ans=0;
	ll left,right,mid;
	left=0;
	right=ll(1)<<62;
	while(left<=right)
	{
		mid=(left+right)>>1;
		if(ok(mid))
		{
			ans=mid;//为了得到最小。
			right=mid-1;
		}
		else
			left=mid+1;
	}
	return ans;
}

int main()
{
	int t,n,i;
	ll a,b;
	getPrime();
	while(scanf("%d",&t)!=EOF)
	{
		while(t--)
		{
			memset(num,0,sizeof num);
			scanf("%d",&n);
			for(i=0;i<n;i++)
			{
				scanf("%I64d %I64d",&a,&b);
				cal(a,b);
			}
			ll ans=0;
			ans=bfind();
			printf("%I64d\n",ans);
		}
	}
	return 0;
}