POJ【数学】1150 The Last Non-zero Digit

POJ 1150 The Last Non-zero Digit

(这题怎么跑到组合数学里面来了???)

题目大意

◆题目传送门◇

N ! ( N − M ) ! \frac{N!}{(N-M)!} (NM)!N!的最后一位非零数字。

分析

我们可以将所有的因数 10 10 10去掉,问题就转换为了求这个数的最后一位。

但直接去掉因数 10 10 10有点麻烦,我们稍退一步,可以先去掉 2 a × 5 b 2^a\times 5^b 2a×5b

这个问题等价于当 n ! = a p e n!=ap^e n!=ape a a a无法被 p p p整除)时,求解 e e e

一个显然的结论是 e = n / p + n / p 2 + n / p 3 + … e=n/p+n/p^2+n/p^3+\dots e=n/p+n/p2+n/p3+。(具体可参考《挑战程序设计竞赛(第二版)》293-294页)

我们进一步可以发现,当 b > a b>a b>a时,答案一定是 5 5 5

接下来讨论 b ≤ a b\le a ba的情况:

我们现在只需要知道 3 , 7 , 9 3,7,9 3,7,9的个数就可以获得答案。因为 3 , 7 , 9 3,7,9 3,7,9的末尾都是以 4 4 4为周期出现。

为了求解方便,我们直接讨论 n ! n! n!

我们将 1 , 2 , 3 , … , N 1,2,3,\ldots,N 1,2,3,,N分为两个序列: 2 , 4 , 6 … 2,4,6\ldots 2,4,6 1 , 3 , 5 , … 1,3,5,\ldots 1,3,5,,即偶数序列和奇数序列。

对于偶数序列,我们只需将它除 2 2 2即可递归转化为奇数序列。对于奇数序列,我们可以发现,每 10 10 10个数字中就有 3 , 7 , 9 3,7,9 3,7,9各一,但又因为其中有 5 5 5的倍数,所以继续除 5 5 5递归。

至此我们得到了所有的因数 2 , 5 , 3 , 7 , 9 2,5,3,7,9 2,5,3,7,9的个数。其中 2 , 5 2,5 2,5可以对消为 2 a − b 2^{a-b} 2ab,我们就可以利用这些数的 N N N次方尾数是 4 4 4个一循环即可。

参考代码

#include<cstdio>
#include<algorithm>
using namespace std;

const int T[][4]={
	{6,2,4,8},//2^4,2^1,2^2,2^3
	{1,3,9,7},//3^4,3^1,3^2,3^3
	{1,7,9,3},//7^4,7^1,7^2,7^3
	{1,9,1,9},//9^4,9^1,9^2,9^3
};

int N,M;

int Calc(int num,int t) {
	return num==0?0:(num/t+Calc(num/t,t));
}

int g(int num,int t) {
	return (num==0)?0:(num/10+(num%10>=t)+g(num/5,t));
}
int cal(int num,int t) {
	return num==0?0:(cal(num/2,t)+g(num,t));
}

int main() {
	#ifdef LOACL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
	while(scanf("%d %d",&N,&M)!=EOF) {
		int num2=Calc(N,2)-Calc(N-M,2);
		int num5=Calc(N,5)-Calc(N-M,5);
		if(num5>num2) {
			puts("5");
			continue;
		} else {
			int ans=1;
			int num3=cal(N,3)-cal(N-M,3);
			int num7=cal(N,7)-cal(N-M,7);
			int num9=cal(N,9)-cal(N-M,9);
			if(num2>num5)
				ans*=T[0][(num2-num5)%4],ans%=10;
			ans*=T[1][num3%4],ans%=10;
			ans*=T[2][num7%4],ans%=10;
			ans*=T[3][num9%4],ans%=10;
			printf("%d\n",ans);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值