2018ICPC南京网络赛 J sum (线性筛 + 思维)

首先,对于每一个素数x,f (x) = 2。对于 x 含有一个大于等于三次的素因子,f (x) = 0。

然后是线性筛的过程,对于i * prime [ j ] 有几种情况:

如果 i % prime[ j ] == 0 :

            如果 i % ( prime[ j ] * prime[ j ] ) == 0 那么,无论把素因子放到那一边,另一边肯定有素因子的平方或三次方,所以这种情况下 f [ i * prime[ j ] ] = 0

             如果不为0,那么只能把prime [ j ] 各放一边,所以 f [ i * prime[ j ] ] = f [i / prime[ j ]]

如果不为0 那么prime[j] 可以放在两边,所以f [ i * prime[ j ] ] = 2*f[ i ]

然后求前缀和即可

这个题不算难,但是比赛的时候一点头绪都没有。线性筛都不熟悉,自己还是太菜了,要补的知识点太多。。。

代码:

// zyc 2018/9/3
// ICPC网络赛J 线性筛 + 前缀和

#include 
using namespace std;

typedef long long ll;
const int N = 1e7 + 7;
const int M = 2e7 + 7;
#define rep(i, a, b) for(int i = a; i < b; i ++)
#define per(i, a, b) for(int i = a; i > b; i --)

bool notprime [M];
int prime [N],ans [M];
void init ()
{

    int cnt = 0; notprime[1] = 1; ans[1] = 1;
    rep (i, 2, M) {
        if (! notprime[i]) {
            prime[cnt ++] = i; ans[i] = 2;
        }
        for (int j = 0; j < cnt && i * prime[j] < M; j ++) {
            notprime[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                if ((i / prime[j] % prime[j]) == 0) {
                    ans[i * prime[j]] = 0;
                } else {
                    ans[i * prime[j]] = ans[i / prime[j]];
                }
                break;
            }
            ans[i * prime[j]] = 2 * ans[i];
        }
    }
    rep (i, 2, M) {
        ans [i] += ans[i - 1];
    }
}
int main ()
{
    init();
    int t; scanf ("%d", &t);
    while (t --) {
        int n; scanf ("%d", &n);
        printf ("%d\n", ans[n]);
    }
    return 0;
}

 

你可能感兴趣的:(2018ICPC南京网络赛 J sum (线性筛 + 思维))