如果一个数字存在一个约数是完全平方数,那么小Q就认为这个数是有趣的。
小Q喜欢收集有趣的数字,每找到一个有趣的数,小Q就会变得很开心。
小Q发现12是有趣的,18也是有趣的,它们都是36的约数,而在36的约数中,还有3个数是有趣的,它们是4、9、36。
小Q很好奇,在a~b里每个数字各有多少个有趣的约数,由于a和b太大了,所以他只想知道这些个数之和是多少。
例如4有1个有趣的约数,8有2个有趣的约数,9有1个有趣的约数,所以1~10里每个数的有趣约数个数之和是4。
Input
输入数据包括2个数:a, b,中间用空格分隔。(1≤a≤b≤10^9)
Output
输出a~b里每个数字的有趣约数个数之和。
Input示例
1 10
Output示例
4,那么答案就是S(m)-S(n-1);
思路:分块+莫比乌斯;
根据莫比乌斯abs(mul[i]) = 0表示i这个数有平方项因子,abs(mul[i]) = 1表示这个数没有平方项因子。
然后分块计算,前sqrt(n)直接用公式,然后后面的因为(n/i)在一段区间内是相同的值,那么我们只要算出这个区间的长度,这个容斥下就行了,算出区间内符合是含有平方因子的数。
1 #include<bits/stdc++.h> 2 typedef long long LL; 3 using namespace std; 4 bool prime[100005]; 5 LL ak[100005]; 6 LL mul[100005]; 7 const int BufferSize=1<<16; 8 char buffer[BufferSize],*head,*tail; 9 inline char Getchar() { 10 if(head==tail) { 11 int l=fread(buffer,1,BufferSize,stdin); 12 tail=(head=buffer)+l; 13 } 14 return *head++; 15 } 16 inline int read() { 17 int x=0,f=1;char c=Getchar(); 18 for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; 19 for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; 20 return x*f; 21 } 22 LL slove(LL n); 23 int akk[100005]; 24 int main(void) 25 { 26 int cn = 0; 27 mul[1] = 1;int ap = 0; 28 for(int i = 2; i <= 100000; i++) 29 { 30 if(!prime[i]) 31 { 32 ak[cn++] = i; 33 mul[i] = -1; 34 } 35 for(int j = 0; j < cn&&(LL)ak[j]*i<=100000; j++) 36 { 37 if(i%ak[j]) 38 { 39 prime[i*ak[j]] = true; 40 mul[i*ak[j]] = -mul[i]; 41 } 42 else 43 { 44 prime[i*ak[j]] = true; 45 mul[i*ak[j]] = 0; 46 break; 47 } 48 } 49 if(mul[i])akk[ap++] = i; 50 } 51 LL n,m; 52 n = read(),m=read(); 53 LL c = sqrt(n); LL sum = 0; 54 sum = slove(m)-slove(n-1); 55 printf("%lld ",sum); 56 return 0; 57 } 58 LL slove(LL n) 59 { if(n == 0)return 0; 60 LL c = sqrt(n);LL sum = 0; 61 for(int i = 2;i <= c;i++) 62 { 63 if(!mul[i]) 64 { 65 sum += n/i; 66 } 67 } 68 for(int i = 1;i <= n/c-1;i++) 69 { 70 LL a,b; 71 a = n/(i+1); 72 b = n/i; 73 a++;LL v = 0; 74 for(int j = 0;akk[j] <= sqrt(b);j++) 75 { 76 sum -= (mul[akk[j]]*((b)/(akk[j]*akk[j])-(a-1)/(akk[j]*akk[j])))*i; 77 } 78 } 79 return sum; 80 }