题目大意:就是找一个数拆成两个无平方因子的组合数,然后求个前缀和 ;
分析:运用筛法的思想 ,
因为有序对是由两个合法的数字组成的,所以只要保证第一个数合法,第二个数也合法就行,找出合法的第二个数字的个数就可以用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)等两边数字相同的情况。
乘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 ", L, sum[R] - sum[L-1]); ans += (sum[R] - sum[L]) * 2 + 1; } printf("%lld ", ans); } return 0; }