ACM-ICPC 2018 南京赛区网络预赛 sum(欧拉筛)

学了欧拉筛之后找了这道题来练练手,结果写了好久才过了
题意:
一个数字可以由多个数字相乘构成,统计一个数能有几种构成方法f(i),但是相乘的数字必须是无平方数,例如:6=2x3=3x2=1x6, 但是 8=2x4=2x2^2这样就不行。a x b 和b x a要算两个,a x a算一个。最后需要输入一个数n,输出1~n所有数构成方法的和
理解:
需要得到无平方数只有两种可能:1和素数,所以我们需要找到可能实现的素数,如果用暴力的方法会超时,那么可以选择使用欧拉筛的方式来做,先打表再输入n直接输出结果,所以在每一轮的筛选过程中就要顺便把一些合数的构成方法f(i)求出来
一个数不是规定了必须只能由两个数相乘构成

  • 当n为质数时,n= 1 x n = n x 1,则f(n)=2;
  • 当n为1时,1=1 x 1,则f(1)=1。

我们可以假设质数为p,质数的指数为i(i=1、2、3……),则n= p^i * x

  • 当i=1时,n = p * x (例如 6=2 x 3) , f(n) = f( p ) * f(x);
  • 当i=2时,n = p * p * x(例如4=2 x 2 x 1) ,f(n) = f(x);
  • 当i>=3时,就没有无平方数了(例如8=2 x 2 x 2 x 1)

完整代码如下:

#include<cstdio>
int book[20000001] ;		//筛素数
int prime[20000001] ;		//存素数
int f[20000001] ;			//存构成组合情况数
int sum[20000001] ;			//存前缀和
int main() {
    int count = 0, n, x;
    f[1] = 1 ;				//一定要先把1的组成情况写出来
    for(int i=2; i<20000001; i++) {
        if(book[i] == 0) {		//找出素数
             prime[count++] = i ;
             f[i] = 2 ;			//每个素数的组成情况为2
        }
        for(int j=0; j<count&&i*prime[j]<20000001; j++) {
            int now = i * prime[j] ;	//找出以素数为最小质因子构成的合数
            book[now] = 1 ;
            if(i % prime[j])           			//now=p*i
                f[now] = f[i] * f[prime[j]] ;
            else if((i/prime[j])%prime[j] == 0)  //now=p*p*p*x
                f[now] = 0 ;
            else {                          //now=p*p*x
                 f[now] = f[i/prime[j]] ;
                 break ;
            }

        }
    }
    for(int i=1; i<20000001; i++)		//打表求出前缀和
        sum[i] =sum[i-1] +f[i] ;
    scanf("%d", &n) ;
    while(n--) {
        scanf("%d", &x) ;
        printf("%d\n", sum[x]) ;
    }
    return 0 ;
}

总结:
理解题目很重要!我每次做题特别是英文的题目,理解题目的意思是最困难的,很多次都是一理解了题意马上就懂了
学了一个新知识后要多做这个点的题目来强化

发布了21 篇原创文章 · 获赞 51 · 访问量 3196

猜你喜欢

转载自blog.csdn.net/weixin_44689154/article/details/102176271