SAC E#1 - 一道中档题 Factorial

题目背景

SOL君(炉石主播)和SOL菌(完美信息教室讲师)是好朋友。

题目描述

SOL君很喜欢阶乘。而SOL菌很喜欢研究进制。

这一天,SOL君跟SOL菌炫技,随口算出了n的阶乘。

SOL菌表示不服,立刻就要算这个数在k进制表示下末尾0的个数。

但是SOL菌太菜了于是请你帮忙。

输入输出格式

输入格式:

本题包含多组数据。

每组输入仅包含一行:两个整数n,k。

输出格式:

对于每组输入,输出一个整数:n!在k进制下后缀0的个数。

输入输出样例

输入样例#1:
10 40
输出样例#1:
2

说明

对于20%的数据,n <= 1000000, k = 10

对于另外20%的数据,n <= 20, k <= 36

对于60%的数据,n <= 10^15,k <= 10^12

对于100%的数据,n <= 10^18,k <= 10^16

鬼题

如果k<=10^12是可以稳过的

k<=10^16就只剩pollard Rho(超出提高组模拟范围了)或玄学优化

首先k进制最后x位为0表示n!能整除k数x次(显然而重要的条件)

于是问题变为了n!含有多少个k的因子

k为合数不好处理,分解质因数k=p1^a1*p2^a2*p3^a3.....

对于求n!含k的数量,转变为求p1....的因子数,在除以a1...,取最小值

给出2种方法

1.

n!=(1k*2k*3k*4k*5k...mk)*a

=k^m*m!*a

a为不含k的积,m=n/k

这样就可以log递归求解

2.

含有一个k:n/k

含有二个k:n/k/k

.....

含有p个k:n/(k^p)

把它们相加

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #define count COUNT
 7 using namespace std;
 8 long long prime[100001],mi[100001],tot;
 9 long long n,k,cnt,ans=9223372036854775807,s;
10 long long count(long long p,long long k,long long Mod)
11 {
12   long long num=0,ss=0;
13   while (p)
14     {
15       num+=p/k;
16       if (num>=Mod) ss+=1,num-=Mod;
17       p/=k;
18     }
19   return ss;
20 }
21 int main()
22 {register long long i;
23   while (scanf("%lld%lld",&n,&k)==2)
24    {tot=0;ans=9223372036854775807;
25   long long p=sqrt(k);
26   for (i=2;i<=p;i++)
27     {
28       if (k%i==0)
29     {
30       prime[++tot]=i;
31       cnt=0;
32       while (k%i==0)
33         {
34           k/=i;
35           cnt++;
36         }
37       mi[tot]=cnt;
38     }
39       if (k==1) break;
40     }
41   if (k!=1) 
42     {tot++;
43       prime[tot]=k;
44       mi[tot]=1;
45     }
46   for (i=1;i<=tot;i++)
47     {
48       s=count(n,prime[i],mi[i]);
49       if (ans>s) ans=s;
50     }
51   printf("%lld\n",ans);
52  }
53 }

 

posted @ 2017-10-07 16:06  Z-Y-Y-S  阅读(309)  评论(0编辑  收藏  举报