Wannafly挑战赛25 A 因子

题目链接:https://www.nowcoder.com/acm/contest/197/A

链接:https://www.nowcoder.com/acm/contest/197/A
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

令 X = n!, 给定一大于1的正整数p 求一个k使得 p ^k | X 并且 p ^(k + 1) 不是X的因子。

输入描述:

两个数n, p (1e18>= n>= 10000 >= p >= 2)

输出描述:

一个数
表示k
示例1

输入

复制
10000 12

输出

复制
4996

大致讲一下,可能不是很清楚,见谅。刚刚我队友和我说涉及除法的时候常常要想到把一个数字拆分成素数,在这题里面好像真是这样。
题目告诉我们p^k是n!的因子,一个数是另一个数的因子,那么这个数有的东西,另一个数一定也有,并且数量上一定大于等于因子具有的数量。

p这个数字一定可以把它拆分成素数相乘的形式,假设是(a^n1)*(b^n2)*(c^n3)*...这里a,b,c是素数,n1,n2,n3是指数。
n!也是可以拆分成素数相乘的形式的,尽管他可能贼大:(a^p1)*(b^p2)*(c*p3)*...*(A^k1)*(B^k2)*...,这里a,b,c,A,B都是素数,p1,p2
k1,k2是指数,因为p肯定是n!的因子,所以p有的素数n!也有(a,b,c这些),n!有的p不一定有(A,B这些,不理他)。

然后因为p^k是n!的因子,所以在p上面加一个指数( (a^n1)*(b^n2)*(c^n3)*... )^k
我们可以知道 n1*k<=p1
n2*k<=p2
n3*k<=p3...
因为p^k是n!的因子啊(仔细想一下)
然后现在我们让k增加1,使得p^(k+1)不是n!的因子,什么情况下p^(k+1)不是n!的因子呢?当然是在p^(k+1)有的东西n!不一定都有的情况下。
我们看上面的式子:
       n1*k<=p1
n2*k<=p2
n3*k<=p3... 这是不是p^k有的n!都有
那要是n1*(k+1)>p1或n2*(k+1)>p2或n3*(k+1)>p3...只要满足其中的一个条件p^(k+1)就一定不是n!的因子了是吧。
把上面的式子变换一下:
      1.0*p1/n1>=k      
      1.0*p2/n2>=k 并且 p1/n1<k+1,p2/n2<k+1,p3/k3<k+1其中一个成立
      1.0*p3/n3>=k
那我是不是只要找的pi/ni取整最小的那个数字就可以了,k就是这个取整之后的数字。
感觉越讲越麻烦了......

思路:把p里面的素数找出来,同时算出指数,然后把n!里对应的素数的指数算出来,找后者除以前者取整的最小值就可以了。
然后n!假如我要求a这个素数的指数怎么求呢?
假设我要求8!里面素数2的指数
1 2 3 2*2 5 2*3 7 2*2*2
step1:把1到n里至少有一个2作为因子的数字的数量数量加一遍 2 2*2 2*3 2*2*2 一共加4次
step2:至少有两个2(就是2*2)作为因子的数量加一遍 2*2 2*2*2 加2次
step3:至少有三个2的 : 2*2*2 加1次
num=7.
我的代码(有问题的代码):
ll cal(ll n,ll a)//求n!里素数a的指数num
{
    ll num=0;
    for(ll i=a;i<=n;i*=a)
    num+=n/i;
    return num;
}

这里的问题就是会数据溢出,因为n会高达1e18,在i<n的情况下,i*a可能会溢出。

所以正确代码:

ll cal(ll n,ll a)
{
    ll num=0;
    while(n/=a)
    {
        num+=n;
    }
    return num;
}

额,太累了,不解释,看懂我的有问题的代码,那么这个更加正确的应该没问题。

全代码:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<vector>
#include<fstream>
#include<set>
#include<cstdio>
#include<string>
#include<deque> 
using namespace std;
#define eps 1e-8
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 10005
/*struct point{
    int u,w;
};
bool operator <(const point &s1,const point &s2)
{
    if(s1.w!=s2.w)
    return s1.w>s2.w;
    else
    return s1.u>s2.u;
}*/
ll n,m,ans,p;
ll cal(ll n,ll a)
{
    ll num=0;
    while(n/=a)
    {
        num+=n;
    }
    return num;
}
int main()
{
    cin>>n>>p;
    ll ans=1e18+9;
    for(ll i=2;i<=p;i++)
    {
        ll num1=0;
        if(p%i==0)
        {
            while(p%i==0)
            {
                num1++;
                p/=i;
            }
            ll num2=cal(n,i);
            ans=min(ans,num2/num1);
        }
    }
    cout<<ans<<endl;
    return 0;
}

 

 

转载于:https://www.cnblogs.com/6262369sss/p/9723270.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值