ACM-ICPC 2018 南京赛区网络预赛 J sum (找一个数拆成两个无平方因子的组合数)

题目大意:就是找一个数拆成两个无平方因子的组合数,然后求个前缀和  ;

 

分析:运用筛法的思想 , 

 因为有序对是由两个合法的数字组成的,所以只要保证第一个数合法,第二个数也合法就行,找出合法的第二个数字的个数就可以用sum前缀和来算,所以L就是第一个数,R=n/L就是最大的第二个数,这里又规定了第二个数从L+1开始,所以sum[R]-sum[L]就是L+1~R合法数字的个数

sum[i] 表示的是小于等于i 的合法因子数 , sum[R]-sum[L] , 就是表示因子大于L,小于等于R,的个数

 L代表第一个数字
乘2是因为比如说枚举到(2,6)的时候也要把(6,2)加进去,而因为L只到sqrt(n),所以(6,2)是不会枚举到的,所以要在这里计算进去,加1就是加上比如(2,2),(3,3)等两边数字相同的情况。
 
#include <cstdio>
#include <cstring>
#include <cmath>

const int UP = 2e7 + 5;
bool can[UP];
int sum[UP];

void constant() {
    memset(can, true, sizeof(can));
    int u = sqrt(UP+0.5);
    for(int i = 2; i <= u; i++) {
        int v = i * i;
        for(int t = v; t < UP; t += v) can[t] = false;
    }
    for(int i = 1; i < UP; i++) {
        sum[i] = sum[i-1] + 1;
        if(!can[i]) sum[i]--;
    }
}

int main() {
    constant();
    int T, n;
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        int u = sqrt(n+0.5);
        long long ans = 0;
        for(int L = 1; L <= u; L++) {
            if(!can[L]) continue;
            int R = n / L;
            //printf("L = %d  sum = %d\n", L, sum[R] - sum[L-1]);
            ans += (sum[R] - sum[L]) * 2 + 1;
        }
        printf("%lld\n", ans);
    }
    return 0;
}
View Code

 

posted @ 2018-09-03 21:15  shuai_hui  阅读(169)  评论(0编辑  收藏  举报