您的位置:首页 > 其它

一道因数分解的相关数学题

2010-11-08 19:49 183 查看
题目地址http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=222



此为数学题。



题目要求求出N!的最后一位(即最低位)非零位是多少。



分析过程:



我们得先明确一点: 乘积中的因子10只有2,5两质因数相乘才能得到。

可以先来观察下乘积末尾不为0的情况,因此我们试着把乘积中5的倍数均去掉。



① 当 0<=N<10

那么 1~9 N! 中最后一非零位分别为 1,1,2,6,4,4,4,8,4,6 (已经去掉5)

因为事先去掉了5,所以当我们把5补上的时候,相当于最后一位数均除以2。

于是正确的输出应该是 1,1,2,6,4,2,2,4,2,8。(

这里可能有人会有疑问,为什么最后一位不是3呢?这是因为乘数中的因子2比5要多很多,所以N!总是偶数

)



② 剩下的情况

由①可知 当 0<N<10 时,可得 1,2,6,4,4,4,8,4,6。

那对于N的其他取值呢?

可以发现,乘数若以九个为一组,每组各位由1~9,其他位相同。那么都是遵循这一规律的。

由于9!(去5)位数为6,所有组的个位乘积为6*6...6*6。最后个位还是6。

因此现在把注意力转移到N的最后一位数字(即N%10)。

单个数字的乘积末尾情况已经给出了。

所以现在的任务就是把5的倍数补回去。

5的倍数: 5 10 15 20 ... 5k 5(k+1)

我们将每个数提取一个5,那么得到1 2 3 4 ... k k+1。 怎么样,又回到过去了吧? 是不是想到递归了呢。

若答案是f(N), 那么现在这个便是f(N/5)。

还有提取的5^(N/5)呢?每成个5,相当于除以2,因此





F([N/5]) * table[N的尾数] * 6

F(N) = ---------------------------------------- (N > 10) (里面的table便是先前给出的序列,这个公式直接从网上复制了 ^_^)

2^([N/5] MOD 4)



这里MOD4的原因是(2,4,6,8 (刚说了,最后位总是偶数) )除2是以4次为一循环的,可以笔算下。





好了,分析完毕,你可以用递归或者迭代的计算方式。



我采用了迭代的方法,代码如下:



#include <stdio.h>
#include <string.h>
int s1[10] = {1,1,2,6,4,4,4,8,4,6};
int s2[10] = {1,1,2,6,4,2,2,4,2,8};
int s3[4][4] = {2,6,8,4,4,2,6,8,6,8,4,2,8,4,2,6};
char str[200];
int main() {
	int len,i,j,tt,c,w,t;
	while(gets(str)) {
		for(i=0; str[i]!=0; i++) {
			str[i]^=48;
		}
		len = i;
		if(len == 1) {
			printf("%d/n", s2[str[0]]);
			continue;
		}
		w=1;tt=0;j=0;
		while(j<len){
			w*=s1[str[len-1]];
			w%=10;
			for(c=0, i=j; i<len; i++) {
				t = str[i];
      				str[i] = (c*10+str[i])/5;
				c = t%5;
			}
			tt += (str[len-2]*10+str[len-1])%4;
			tt %= 4;
			j+=!str[j];
		}
		printf("%d/n",s3[(w*6%10)/2-1][tt]);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: