描述
给你一个正整数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分解成素因子相乘后各个素因子对应的指数 样例输入
-
2 5 53
样例输出 -
3 1 1 49 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。
。。。