zoukankan      html  css  js  c++  java
  • 【JZOJ5791】阶乘【二分】【数论,数学】

    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/5791
    题目图片:
    http://wx2.sinaimg.cn/mw690/0060lm7Tly1fvxbuy446bj30j608kglm.jpg
    http://wx3.sinaimg.cn/mw690/0060lm7Tly1fvxbuy44q9j30j40bbt8r.jpg
    给出nn个数a[1],a[2]...a[n]a[1],a[2]...a[n],求a[1]×a[2]×...×a[n]a[1]\times a[2]\times ...\times a[n]m!m!因数的最小的mm


    思路:

    首先,我们可以把这nn个数分解质因数,并将每个质因数存在一个桶里。
    那么我们设分解后有k[1]k[1]x[2]x[2]k[2]k[2]x[2]...k[m]x[m]x[2]...k[m]个x[m],那么原本的a[1]×a[2]×...×a[n]a[1]\times a[2]\times...\times a[n]就变成了:
    x[1]k[1]×x[2]k[2]×...×x[m]k[m]x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]}
    其实也就是说,将m!分解质因数后一定含有k[1]个x[1],k[2]个x[2],一直到k[m]个x[m]
    我们知道,如果m!m!分解质因数后含有x[1]k[1]×x[2]k[2]×...×x[m]k[m]x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]},那么(m+1)(m+1)!就一定含有x[1]k[1]×x[2]k[2]×...×x[m]k[m]x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]}
    原因很简单。

    证:
    T=x[1]k[1]×x[2]k[2]×...×x[m]k[m]T=x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]},那么由于m!m!分解质因数后含有TT,那么m!m!就可以写成TxTx,其中xx为正整数。
    由于
    (m+1)!=m!×(m+1)=Tx(m+1)(m+1)!=m!\times (m+1)=Tx(m+1)
    所以(m+1)(m+1)!就一定含有x[1]k[1]×x[2]k[2]×...×x[m]k[m]x[1]^{k[1]}\times x[2]^{k[2]}\times...\times x[m]^{k[m]}
    证毕。

    所以,也就是说,m!m!里含有的因式(m+1)(m+1)一定含有,那么(m+2)(m+2)也含有,(m+3)(m+3)也含有。。。
    所以,这个阶乘很明显是单调的。
    那么就可以二分答案qq。若qq!含有k[1]k[1]x[1]x[1]k[2]k[2]x[2]...k[m]x[2]...k[m]x[m]x[m],那么q!q!就是合法的解,由此又可以得到大于qq的数的阶乘也是合法的解。所以最小的答案就在[1,q][1,q]中。
    否则就在[q+1,MAXN][q+1,MAXN]中。
    MAXNMAXN的话设大一点就好了。反正二分又不会很多次。
    时间复杂度:O(nn+nlogn)O(n\sqrt{n}+nlogn)


    代码:

    #include <cstdio>
    #include <cmath>
    #define ll long long
    #define N 5000100
    using namespace std;
    
    int n,m,l,r,mid,num[N];
    
    bool check(int x)
    {
    	int sum;
    	ll y;
    	for (int i=2;i<=N;i++)
    	{
    		if (!num[i]) continue;
    		sum=0;
    		y=(ll)i;
    		while (y<=(ll)x)
    		{
    			sum=sum+(x/(int)y);  //记录有多少个i
    			if (sum>num[i]) break;
    			y*=i;
    		}
    		if (sum<num[i]) return false;  //不够
    	}
    	return true;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	int x;
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d",&x);
    		for (int j=2;j*j<=x;j++)
    		 while (!(x%j))
    		 {
    		 	num[j]++;  //分解质因数
    		 	x/=j;
    		 }
    		if (x>1) num[x]++;
    	}
    	l=1;
    	r=N-1;
    	while (l<=r)
    	{
    		mid=(l+r)/2;
    		if (check(mid)) r=mid-1;
    		 else l=mid+1;
    	}
    	printf("%d\n",r+1);
    	return 0;
    }
    
  • 相关阅读:
    RSA加密
    各种正则
    用Fragment制作的Tab页面产生的UI重叠问题
    Android源码下载
    Android Studio使用百度地图问题总结
    Android获取网络类型
    Android Studio类中实现Serializable自动生成serialVersionUID
    【Android开发】如何设计开发一款Android App
    UIViewController生命周期
    微信支付开发经验分享
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998543.html
Copyright © 2011-2022 走看看