NEFU 118 - n!后面有多少个0 & NEFU 119 - 组合素数 - [n!的素因子分解]

首先给出一个性质:

n!的素因子分解中的素数p的幂为:[ n / p ] + [ n / p² ] + [ n / p³ ] + ……

 

举例证明:

例如我们有10!,我们要求它的素因子分解中2的幂;

那么,根据公式有 [ 10 / 2 ] + [ 10 / 4 ] + [ 10 / 8 ] (后面例如[10/16]之类的都为0);

显然[ 10 / 2 ] = 5,代表了从1~10中有几个数是2的倍数:2,4,6,8,10;它们每个数都为10!提供了1个2;

之后[ 10 / 4 ] = 2,代表了从1~10中有几个数是4的倍数:4,8;那加上这两个数是为什么呢?因为在前面已经提供了5个2的基础上,4和8可以各再多提供1个2;

[ 10 / 8 ] = 1,代表了从1~10中有几个数是8的倍数:8;因为同样的,在前面的基础上,8又可以再提供一个2;

这样,可以说这个公式为什么是这样的,已经很明显了;

 

然后开始看题目:

                                                                                                                                                                                                            

题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=118

Time Limit:1000ms Memory Limit:65536K

Description

从输入中读取一个数n,求出n!中末尾0的个数。

Input

输入有若干行。第一行上有一个整数m,指明接下来的数字的个数。然后是m行,每一行包含一个确定的正整数n,1<=n<=1000000000。

Output

对输入行中的每一个数据n,输出一行,其内容是n!中末尾0的个数。

Sample Input

3
3
100
1024

Sample Output

0
24
253

 

题解:

显然的,这样的数据范围下,我们不可能直接算出n!等于多少,那么我们就要来考虑n!的因式分解;

由于我们要求n!的末尾有多少个0,不难想到每个0都代表了n!的素因子中有一个2和一个5,这样才能产生一个10,进而在末尾产生一个0;

那么,我们要根据上面的定理,有:

f(2) = [ n / 2 ] + [ n / 4 ] + [ n / 8 ] + ……

f(5) = [ n / 5 ] + [ n / 25 ] + [ n / 125 ] + ……

显然,对于[ n / p^k ],不管k有多大,[ n / p ^ k ]都始终大于等于零;

显然,f(2)的项数应该要不会少于f(5),同时[ n / 2^k ]与不会小于[ n / 5^k ];

所以,n!的素因子分解式中,2的幂次数肯定多多于5的幂次数,这样,我们就可以转化为求n!的素因子分解中5的幂次数为多少;

那么,根据公式,就不难得到答案;

 

AC代码:

 1 #include<cstdio>
 2 int n,ans;
 3 int main()
 4 {
 5     int t;
 6     scanf("%d",&t);
 7     while(t--)
 8     {
 9         scanf("%d",&n);
10         ans=0;
11         for(int i=n/5;i>0;i/=5) ans+=i;
12         printf("%d\n",ans);
13     }
14 }

 

                                                                                                                                                                                                            

题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=119

Time Limit:1000ms Memory Limit:65536K

Description

小明的爸爸从外面旅游回来给她带来了一个礼物,小明高兴地跑回自己的房间,拆开一看是一个很大棋盘(非常大),小明有所失望。不过没过几天发现了大棋盘的好玩之处。从起点(0,0)走到终点(n,n)的非降路径数是C(2n,n),现在小明随机取出1个素数p, 他想知道C(2n,n)恰好被p整除多少次?小明想了很长时间都没想出来,现在想请你帮助小明解决这个问题,对于你来说应该不难吧!

Input

有多组测试数据。
第一行是一个正整数T,表示测试数据的组数。接下来每组2个数分别是n和p的值,这里1<=n,p<=1000000000。

Output

对于每组测试数据,输出一行,给出C(2n,n)被素数p整除的次数,当整除不了的时候,次数为0。

Sample Input

2
2 2
2 3

Sample Output

1
1

 

题解:

依然是使用上面那个定理的题目;

那么如何求得a和b呢?

显然,根据上面的公式,就有:

a = [ 2n / p ] + [ 2n / p² ] + [ 2n / p³ ] + ……

b = [ n / p ] + [ n / p² ] + [ n / p³ ] + ……

最后输出的答案就是a-2*b;

 

AC代码:

 1 #include<cstdio>
 2 typedef long long ll;
 3 ll n,p;
 4 ll calc(ll n,ll p)
 5 {
 6     ll cnt=0;
 7     for(ll i=n/p;i>0;i/=p) cnt+=i;
 8     return cnt;
 9 }
10 int main()
11 {
12     int t;
13     scanf("%d",&t);
14     while(t--)
15     {
16         scanf("%lld%lld",&n,&p);
17         printf("%lld\n",calc(2*n,p)-2*calc(n,p));
18     }
19 }

 

posted @ 2017-09-24 20:14  Dilthey  阅读(468)  评论(0编辑  收藏  举报