题目链接 题目 (最近真是快自闭了。。。 要找一种置之死地而后生的学习方法- 。-)
原理:
比如f(6)=4 可选的元素有2和3 现在你要把它分成两部分,那我们不妨只考虑第一部分的取法
就是1 2 3 6,另一部分就是(6/第一部分) (是除以)
也就是对于每个元素,可以选取或者不取
所以答案就是 2^(选项)
2^是
2的质因子个数次方 当然是经过上面处理的剩下的质因子个数
经过我们前两步处理后,剩下的质因子个数就是可选择的质因子个数了
所谓可选择的质因子个数,就是在式子n=a*b中,可以在a,也可以在b
那么对于每个可选的质因子个数都有两种选择,所以答案就是2的可选质因子个数次方
Q: 3次的为什么就全是0了
A: 设这个质数为p,既然你已经有了一个p^3(p的3次方),那么你无论怎么分,两边终有一边的次数>=2
p^4 p^5都是0
Q: P^2
A: p^2可以劈开成两半 然后这个质数就不能选择了,所以要减去
比如4 你只能放成2和2 1*4不行
Q: 举个例子 f(30)
A: 2*3*5 所以是8(没有被筛掉的)
注意: 所谓!质因数分解!。。
36分解成的是2*2*3*3 因子个数是2个! 不是有几种表示36的方法!!!
p^1是可选择的意思是,它可以放在a,也可以放在b,所以有两种答案 对其他所有可选择的质数独立,所以答案是2的可选择的质数次
p^3不断往后累加的时候 |
假设这个是6^6^6 就是(6^6^6)*1 *2 *3 |
|
当到达*6的时候其实就是p^4 |
到达*36的时候就是p^5 |
前面置0了,后面就可以继承0的 |
但是可以由p^3推导 |
p^3不断往后累加的时候 |
|
总体原理:
模板参考: hh
欧拉素数筛
复杂度 On
其原理是每个合数都只会被一个质数筛去,因此为 On 线性筛法
关键代码原理是 每个比 i 大的合数,必可以拆分为一个比 i 小的质数和另一个合数之积
int primes[MAXN],tot=0;
bool isPrime[MAXN];
void getPrime()
{
memset(isPrime,true,sizeof(isPrime));
for(int i=2;i<MAXN;i++)
{
if(isPrime[i])
primes[++tot]=i;
for(int j=1;j<=tot;j++)
{
if(i*primes[j]>=MAXN) break;
isPrime[i*primes[j]]=false;
if(i%primes[j]==0) break;//*****
}
}
}
注意 判断的时候只看的是素数组成
把判断素数和 质因子分解搞在一起 高 实在是高
附赠 copy来的 打表程序
#include<iostream>//bits/stdc++.h>
#define ll long long
#define maxn 50//000005
using namespace std;
int T,n;
bool vis[maxn];
int prime[maxn]; int d[maxn];//int num[maxn];
int cnt;
void getprime()//先求素因数个数
{
cnt=0;
for(int i=2;i<=maxn-5;++i)
{
if(!vis[i])
{//在遍历的过程中如果是1的话,那么因子个数是1,这些是没错的
prime[++cnt]=i;
// num[i]=1;
d[i]=1;
}
cout << i<<"i--------"<<endl;
for(int j=1;j<=cnt&&i*prime[j]<=maxn-5;++j)
{
cout << i * prime[j] << endl;
vis[i*prime[j]]=1;
if (!(i%prime[j]))// ==0 chudejin
{
cout<<"除尽了!" << i << " " << prime[j] << " " << endl;
cout << " d " << i * prime[j] << "is d " << i << " " << d[i] << endl;
// cout <<" "<<i*prime[j]<<" "<< d[i] << endl;
// num[i*prime[j]]=num[i]+1;
d[i*prime[j]]=d[i];
break;
}
cout << i << " " << prime[j] << " " << endl;
cout << " d " << i * prime[j]<<"is d " << i<<"+1+1---- " << d[i] << endl;
//cout << d[i] << endl;
d[i*prime[j]]=d[i]+1;
// num[i*prime[j]]=1;
}
}
for (int i = 1; i <= maxn - 5; ++i)
cout << i << " " << d[i] << endl;// << num[i] << endl;
cout << endl;
}
int has[maxn],f[maxn];
void prepare()
{
for(int i=1;i<=cnt;++i)
{
ll x=prime[i]*prime[i];
if(x>maxn-5)break;
x*=prime[i];
if(x>maxn-5)break;
for(int j=x;j<=maxn-5;j+=x)has[j]=-1;
}
for(int i=1;i<=cnt;++i)
{
ll x=prime[i]*prime[i];
if(x>maxn-5)break;
for(int j=x;j<=maxn-5;j+=x)if(has[j]!=-1)has[j]++;
}
for(int i=1;i<=maxn-5;++i)if(has[i]!=-1)
{
int t=d[i]-has[i];
f[i]=(1<<t);
}
for (int i = 1; i <= maxn - 5; ++i) {
cout << "i " << i << " " << has[i]<<" "<<d[i] << endl;
f[i] += f[i - 1];
}
}
int main()
{
scanf("%d",&T);
getprime();
prepare();
while(T--)
{
scanf("%d",&n);
cout<<f[n]<<endl;
}
return 0;
}