题目链接
http://47.110.142.74/contest/1692/problem/2
Description
定义函数f(x)为x的所有质因子乘积。例如:f(4)=2,f(6)=6。
注意:当x为1时,f(1)为1。
输入一个整数n,输出1到n的函数值。
Input
一个整数n(n≤1e6)
Output
n个整数,用空格分开
sample
Input
1
Output
1
Input
5
Output
1 2 3 2 5
题目分析
此题必须用到欧拉筛,此文会讲解欧拉筛。
即使用了欧拉筛也会超时!
因为此题目让你求一个数的所有质因数的乘积,最最最容易想到的就是 在prime数组中从最小的一个找起,验证x%prime【i】是否等于0,如果是就乘上。
这样太慢了,因为题目给出n,我们的工作是对1——n的每一个数都进行这样的操作。
于是 我们想到可以新建立一个数组solu其中储存
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e6+7;
//欧拉筛 用最小的质因数去筛素数
ll prime[maxn];//用来放素数
ll num[maxn];//0一开始全是素数
/*
1 1 1
2 2 2
3 3 3
4 2 2
5 5 5
6 2 3 6
7 1 7
8 2
9 3
10 2 5
*/
//优化版
ll n,i,j,k,l,cou=1;
void oula()
{//全是素数
for(i=2;i<=maxn;i++)
{
if(!num[i])prime[cou++]=i;//如果是素数,储存进prime数组
for(j=1;j<cou;j++)//在当前已有的数组中查找
{
if(i*prime[j]>maxn)break;//超过范围了,退出
num[i*prime[j]]=1;//用最小的质数把所有素数的倍数删除
if(i%prime[j]==0)break;
/*eg.当i=6时,prime数组中已经存入了2 3 5
6*2=12 12就被踢出来了
6%2==0 假设此时不break
j=2 prime【2】=3;
6*3=18 18就被踢出来了
但是! 对于18而言,他的最小质因数是2 2*9=18 due to我们
的i是从1开始循环直到n,所以说 i一定会有等于9的那一天
此时j=1,prime【1】=2 2*9=18 18被踢出来了
这就说明了一个问题 18会被筛掉两次
为了解决这个问题当i%prime【】当前素数==0,break,因为
如果继续的话,就不是用i最小的质因数去筛了
*/
}
}
}
ll solu[maxn];
int main()
{
ll n;
cin>>n;
oula();
for(i=1;i<=n;i++)
solu[i]=1;//初始化为1,为后面的相乘做准备
for(i=1;i<cou;i++)
{
for(j=1;;j++)
{
if(prime[i]*j>n)
break;
solu[j*prime[i]]*=prime[i];
//数组的下标j*prime【i】的因数肯定包括prime【i】
//那我们solu数组是储存答案的 这个答案肯定是呈上prime【i】
}
}
for(i=1;i<=n;i++)
{
if(i==1)
{
cout<<"1 ";
continue;
}
cout<<solu[i];
if(i!=n)
putchar(' ');
}
}
总结
欧拉筛的使用不用多说,原则就是用最小的质因数筛素数
值得一提的是本题怎么让他不超时
solu数组的使用非常关键
他的思想并不是像我们一开始那样,得到一个数n比如是9,我们下意识的反应从后往前推,找9的质因数,之后相乘,这个题因为是很多连续的数,我们可以换一种思想,从每一个质因数出发,让他去构造一个个的数,不用说,这个质数肯定是这个数的因子,那相乘不就是solu的数值吗。
希望得到斧正。