【题解】[nyoj509]因子和阶乘

来源:互联网 发布:mac wmv用什么播放器 编辑:程序博客网 时间:2024/05/27 20:44

描述

给你一个正整数n,把n!=1x2x3x.....xn分解成素因子相乘的形式,并从小到大输出每个素因子的指数,但要保证最后输出的素因子个数不为0。例如825应表示为0,1,2,0,1表示分别有0,1,2,0,1个2,3,5,7,11。

输入
第一行有一个整数n(0<n<10000),表示有n组测试数据;
接下来n行每行有一个整数 m(1<m<10000)
输出
从小到大输出m分解成素因子相乘后各个素因子对应的指数
样例输入
2553
样例输出
3 1 149 23 12 8 4 4 3 2 2 1 1 1 1 1 1 1

---------------------------------------------------------------------------------


比较巧妙的数论题。。。

其实一眼看到,想到的就是对1~m每个数暴力分解一下。。。不过那个10000组数据碉堡了。

然后怎么办。。。我们换一种思考方式。。不求哪一个数的素因子有哪些,而求对于一个素因子a,他在m!出现了几次。

很显然1~m之间只要是a的倍数的数都至少包含一个a,于是numa+=[m/a] (这个数下取整正好就是1~m中a的倍数的个数)

但是这样没统计完,因为还有的数有多个因子a。那么numa再+=[m/(a*a)].

这样还是没有统计完。。。有的数还有两个以上的因子a。。。所以再加[m/(a*a*a)],[m/(a*a*a*a)]...直到要加的这个数为0.

这样素因子a的个数就统计完了。

然后对于2~m之间每一个素数都这样统计一次。。。最后输出就好了(当然要先筛个素数表)

#include<cstdlib>#include<cmath>#include<cstring>#include<iostream>#include<cstdio>#include<algorithm>using namespace std;int prime[10000+10],tail=0;bool flag[10000+10];int n;int main(){for(int i=2;i<=10000;i++){if(!flag[i])prime[tail++]=i;for(int j=0;j<tail&&prime[j]*i<=10000;j++){flag[prime[j]*i]=true;if(i%prime[j]==0)break;}}scanf("%d",&n);for(int i=1;i<=n;i++){int x;scanf("%d",&x);bool first=1;for(int j=0;j<tail&&prime[j]<=x;j++){int now=prime[j];int ans=0;while(1){if(x/now!=0)ans+=x/now;else break;now=now*prime[j];}if(!first)printf(" ");else first=false;printf("%d",ans);}printf("\n");}return 0;}


想到一道很相似的题:

设f(x)=x的所有因子的和。

求Σf(x) mod M(1<=x<=n).

直接求一个f(x)的话可以转换为一堆等比数列相乘。。。(求等比数列的话可以用一个类似快速幂的方法。。。还可以直接套公式。。。不过套公式比较麻烦,因为这个数很大,又包含除法,不能在中途直接取模,非要硬做估计要写高精度吧。。。不过有两种改进思路:1.边乘边除 2.当M为一个质数的话可以把除法转化为乘逆元)

但是这道题并不需要求出每个f(x),这样不仅比较复杂,还会超时。。

也是上一道题的思路:枚举因子a(不一定是素因子),算出1~n中有多少个数有这个因子,记为b。。。(其实就是多少个数是a的倍数)。。。然后ans+=a*b。

。。。

0 0
原创粉丝点击