题意:
求1~n以内的无平方因子数的个数。
思路:
利用类似筛选法把100010的素数标记出来(预处理)
然后通过容斥原理,把有平方因子数的个数算出来,那总个数-有平方因子个数 = 答案了
n之内有平方因子的数的个数sum = n/(2^2) + n/(3^2)+……+n/(k^2) - n/(2^2 * 3^2)-……+……。
Tips:
所谓容斥原理,其实举一个简单的例子就是:一个班里a个同学喜欢吃苹果,b个同学喜欢吃香蕉。问这个班有多少个同学。
如果自己算的话就是a + b - a∩b
这题也一样,把含2的k次方的个数算出来,含3的k次方的个数算出来,含5的k次方的个数算出来,含pri[i]的k次方的个数算出来........然后减去既含2的k次方也含3的k次方的个数,既含3的k次方也含5的k次方....既含pri[i]的k次方也含pri[i+1]的k次方....加上既含2的k次方也含3的k次方也含5的k次方..既含pri[i]的k次方也含pri[i+1]的k次方也含pri[i+2]的k次方的个数...
容斥原理即包含个数为偶数的前面的符号为加,个数为奇数的前面的符号为减..
主要是递归来解决容斥原理那里有点难理解,但是其实就是递归的时候把这一层的运算结果当做下一层的输入,这样就可以完成加加减减的操作了..
Code:
View Code
1 #include <stdio.h> 2 #include <cstring> 3 #include <cmath> 4 #include <ctime> 5 #include <algorithm> 6 using namespace std; 7 8 int pri[1000010]; 9 bool vis[1000010]; 10 long long n; 11 int c; 12 13 long long dfs(int d, long long t) { 14 long long sum = 0; 15 while(d < c && (long long)pri[d]*pri[d] <= n/t) { 16 sum += n/(t*pri[d]*pri[d]) - dfs(d+1, t*pri[d]*pri[d]); 17 d++; 18 } 19 return sum; 20 } 21 22 int main() 23 { 24 int T; 25 long long ans; 26 c = 0; 27 memset(vis, 0, sizeof(vis)); 28 for(int i = 2; i < 1000010; ++i) 29 if(!vis[i]) { 30 pri[c++] = i; 31 for(int j = i*2; j < 1000010; j += i) vis[j] = true; 32 } 33 34 while(EOF != scanf("%d", &T)) 35 while(T--) { 36 scanf("%lld", &n); 37 ans = dfs(0, 1); 38 printf("%lld\n", n-ans); 39 } 40 return 0; 41 }
链接:http://acm.uestc.edu.cn/problem.php?pid=1720