算数基本定理推论

题目链接:http://59.69.128.200/JudgeOnline/problem.php?pid=416

题目大意:

给你十个数A1,A2,A10.范围都是0到10000以内。N是这十个数相乘后的结果。求N的因子个数的个位数字。


解题思路:

这是很久以前抗电网赛的一道题目,其实也就是一个数论题。

用到的知识就是算数基本定理推论:

任一个大于1的整数a都能够唯一的写成

a=p1^a1*p2^a2……pk^ak > 0.

其中p1<p2<……<pk且pk为素数。


然后a的因子个数就是(a1 + 1)*(a2 + 1)*(a3 + 1)……*(ak + 1)。


解决这个问题需要注意地的方有:

素数打表问题,因为每个数都是10000以内的数,所以需要知道100以内的素数都是什么(至于为什么10000这个数只需要求出开方后的数字以内的素数,好像某个数学家证明过吧。。。。可怜

1.我用的打表方法是先把is_prim[i]全部初始化为1.然后从2开始,如果这个数标记为1,则把它的所有倍数全部标记为0(成倍肯定不是素数)。

这样外层循环100次,就可以求出100以内的素数,然后新开一个数组,将100以内的素数顺序记录下来,就可以处理10000以内的素数问题了。但是值得我们特别注意的是:这里如果素数处理后结果不为1,说明它含有大于100的素数,我们不需要处理,它肯定是素数

2.我用map<int,int>ans来记录素数出现的次数。之后循环一遍就可以求出结果。


代码如下:

#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<map> #include<algorithm> using namespace std; int num[10], pre[105]; map<int, int> ans; //存素数个数 bool is_prim[105]; int k; void prim() //素数打表 { k = 0; memset(is_prim, 1, sizeof(is_prim)); //标记素数 for(int i = 2; i < 105; ++i) { if(is_prim[i]) for(int j = i; j * i < 105; ++j) is_prim[i * j] = 0; //倍数剔除 } for(int i = 2; i < 105; ++i) if(is_prim[i]) pre[k++] = i; //顺序记录素数 } int main() { int ncase, count, sum, result; scanf("%d", &ncase); prim(); //素数打表 while(ncase--) { ans.clear(); //容易忘。。。。 sum = 1; result = 1; for(int i = 0; i < 10; ++i) { scanf("%d", &num[i]); sum = num[i]; for(int j = 0; j < k; ++j) //k为100以内素数个数 { while(sum % pre[j] == 0) { ans[pre[j]]++; sum /= pre[j]; } } if(sum != 1) //特别注意的地方!~ ans[sum]++; } map<int, int>::iterator a; for(a = ans.begin(); a != ans.end(); ++a) //map的索引就是素数 result = (result * (a->second + 1)) % 10; printf("%d\n", result); } return 0; }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值