算数基本定理推论

来源:互联网 发布:丝塔芙淘宝官方旗舰店 编辑:程序博客网 时间:2024/04/30 08:47

题目链接: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;}



原创粉丝点击