当前位置: 代码迷 >> 综合 >> 洛谷10月月赛R1·浴谷八连测R1·提高组 一道中档题 Factorial
  详细解决方案

洛谷10月月赛R1·浴谷八连测R1·提高组 一道中档题 Factorial

热度:46   发布时间:2023-10-29 18:13:32.0

我们考虑,0是由进位造成的,而只有乘起来正好进位才行,所以我们想到把k分解质因数,统计出个数,除一下,找最小的
比如 40是2,2,2,5解释说三个二一个五组成零
因为n很大,n的阶乘分解质因数有小学奥数公式
while(tmp>=q){
toto+=tmp/q;
q=q*s[i];
}
而这个题要分解大数的质因数,可以用Pollard_Rho点这里
进制数很大

#include<cstdio>
#include<cstdlib> 
#include<algorithm>
#include<iostream>
#define ll long long 
using namespace std;
ll s[10000009],num,x,y,tot[10000009];
ll multi(ll a ,ll k,ll p){ll ans=0;while(k){if(k&1) ans=(ans+a)%p;a=(a+a)%p;k>>=1; }return ans;
}
ll qpow(ll a,ll k,ll p){ll ans=1;while(k){if(k&1) ans=multi(ans,a,p);a=multi(a,a,p);k>>=1; }return ans;
}
/*ll prepare(){for(int i=1;i<=5000000;i++){if(!ip[i])pr[++cnt]=i;for(int j=2;j<=cnt,pr[j]*i<=5000000;j++){ip[pr[i]*j]=1;if(!(j%pr[i])) break;}}
}*/
bool Miller_Rabin(ll n){if(n==2) return 1;ll u=n-1,t=0,s=50;while(!(u&1ll))t++,u>>=1;while(s--){ll a=rand()%(n-1)+1;x=qpow(a,u,n);for(int i=1;i<=t;i++){y=x,x=multi(x,x,n);if(x==1&&y!=1&&y!=n-1)return 0; }if(x!=1) return 0;}   return 1;
}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;
}
ll Pollard_Rho(ll n,ll c){ll i=1,k=2,x=rand()%(n-1)+1,y=x;while(i++){x=(multi(x,x,n)+c)%n;ll p=gcd(y-x,n);if(p>1&&p<n) return p;if(x==y) return n;if(i==k) y=x,k<<=1;}
}
void find(ll n,ll c){if(n==1) return ;if(Miller_Rabin(n)) {s[++num]=n;return ;}ll p=n,k=c; while(p==n) p=Pollard_Rho(n,c--);find(p,k);find(n/p,k);
}
ll N,K;
int main(){scanf("%lld%lld",&N,&K);find(K,9999999);sort(s+1,s+num+1);ll j=0;for(ll i=1;i<=num;i++){if(s[i]!=s[i-1]) tot[++j]++;else tot[j]++;}ll t1=unique(s+1,s+num+1)-s-1;//去重ll ans=199999999999999;for(ll i=1;i<=t1;i++){    ll tmp=N;ll toto=0;ll q=s[i];while(tmp>=q){toto+=tmp/q;q=q*s[i];}ans=min(toto/tot[i],ans);}printf("%lld",ans);
}