25 欧拉筛 积性函数

A square-free integer is an integer which is indivisible by any square number except 111. For example, 6=2⋅36 = 2 \cdot 36=2⋅3 is square-free, but 12=22⋅312 = 2^2 \cdot 312=22⋅3 is not, because 222^222 is a square number. Some integers could be decomposed into product of two square-free integers, there may be more than one decomposition ways. For example, 6=1⋅6=6⋅1=2⋅3=3⋅2,n=ab6 = 1\cdot 6=6 \cdot 1=2\cdot 3=3\cdot 2, n=ab6=1⋅6=6⋅1=2⋅3=3⋅2,n=ab and n=ban=ban=ba are considered different if a̸=ba \not = ba̸=b. f(n)f(n)f(n) is the number of decomposition ways that n=abn=abn=ab such that aaa and bbb are square-free integers. The problem is calculating ∑i=1nf(i)\sum_{i = 1}^nf(i)∑i=1n​f(i).

Input

The first line contains an integer T(T≤20)T(T\le 20)T(T≤20), denoting the number of test cases.

For each test case, there first line has a integer n(n≤2⋅107)n(n \le 2\cdot 10^7)n(n≤2⋅107).

Output

For each test case, print the answer ∑i=1nf(i)\sum_{i = 1}^n f(i)∑i=1n​f(i).

Hint

∑i=18f(i)=f(1)+⋯+f(8)\sum_{i = 1}^8 f(i)=f(1)+ \cdots +f(8)∑i=18​f(i)=f(1)+⋯+f(8)
=1+2+2+1+2+4+2+0=14=1+2+2+1+2+4+2+0=14=1+2+2+1+2+4+2+0=14.

样例输入

2
5
8

样例输出

8
14

1 欧拉筛的时间复杂度是o(n)的这样的话就可以在时间范围允许的情况下处理出来e8内的数据;

欧拉筛和朴素筛的区别在于不会重复的去筛某一个数字,我们拿12来作为例子的话,在朴素筛的时候

会有3乘以4筛一次,2乘以6筛一次,筛了2次,但是在欧拉筛的时候,我们只会用那个最小素数来把

这个数字筛出来,怎么解决重复出现的问题,如果gcd(a,b)>1(a,b)的话那么a*b的积一定可以分解成为

两个更小的数字的积a*b=a/gcd(a,b)*(gcd(a,b)*b),我们会有a/gcd(a,b)<a<b<gcd(a,b),所以从这个位置开始

后面的多可以这么分解,这样的话我们后面的数字就不会再被重复筛了;

2, 积性函数:对于互质的两个整数a,吧,有f(a,b)=f(a)*f(b);

      我们会发现欧拉函数在没有到达筛的临界点的时候用来筛的两个值全都是互质的,那么有些时候我们可以

     利用这一个性质来打一下表,预处理;

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int Max = 2e7+10;

#define rep(i,s,n) for(int i=s;i<=n;i++)
#define per(i,n,s) for(int i=n;i>=s;i++)

bool visited[Max];
int sum[Max],ans[Max],p[Max],num;

void pri(){
    ans[1]=1;
    sum[1]=1;
    rep(i,2,Max-9){
       if(!visited[i])  visited[i]=true,ans[i]=2,p[num++]=i;//表明这个数字是素数;
       rep(j,0,num-1){
          int k=p[j]*i; // 开始筛素数
          if(k>Max-9) break; //如果越界的话我们就结束
          visited[k]=true;
          int z=p[j]*p[j];
          if(i%p[j])  ans[k]=ans[p[j]]*ans[i]; //如果是互质的话我们就直接采用积性函数的性质;
          else {
            if(i%z){
                ans[k]=ans[k/z];
            }
            else {
                ans[k]=0;
            }//这里就是不互质的情况,就是我们要筛的临界点,之后我们要结束以i为基地的筛对于

            这道题目来说的话就是break;//如果i是p[j]平方的倍数的话,那么你不论怎么分,k的两个

            因数中会用p[j] 的平方,所以这个数字的可以分解的种类数是零,如果是在i仅仅是p[j]的倍数

            不是他平方的倍数的话我们就不能让两个p[j]在一起,那么就是p[j]*a'*p[j]其中p[j]*a'等于i那么这个

           a的分解方案就是我们要的k的分解方案;

          }
       }
       sum[i]=sum[i-1]+ans[i];
    }
}
int main(){
   pri();
   int t;
   scanf("%d",&t);
   while(t--){
    int n;
    scanf("%d",&n);
    printf("%d\n",sum[n]);
   }
   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39792342/article/details/82348783