Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1205 Accepted Submission(s): 546
3 1 1 10 2 10000 72
1 6 260
题意: 在区间[1,n] 里面求出满足 gcd(x, n) >= m 的x有多少个。
转换问题: 我们可以让 n = a * b,x = a * d(b >= d),若gcd(x, n) = a ,那么 b 和 d 一定互质 ,而此时 x的个数即 b 的欧拉函数。
这样问题就变成 在满足 b >= m 的情况下 , 对应n / b 的欧拉函数之和。
结果果断TLE。。。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int euler(int n)//求n的欧拉函数 { int eu = n; int i; for(i = 2; i*i <= n; i++) { if(n % i == 0) { eu = eu * (i-1) / i; while(n % i == 0) n /= i; } } if(n > 1) eu = eu * (n-1) / n; return eu; } int main() { int t; int n, m; int i; int ans; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); ans = 0; for(i = 1; i <= n; i++)//遍历所有可能的 i { if(n % i)//不能整除 continue; /*只处理n % i == 0 的 i */ if(i >= m) ans += euler(n/i);//大于或者等于 m 加上对应的n/i的欧拉函数 } printf("%d\n", ans); } return 0; }
问题出在哪? 很显然,
for(i = 1; i <= n; i++)//遍历所有可能的 i { if(n % i)//不能整除 continue; /*只处理n % i == 0 的 i */ if(i >= m) ans += euler(n/i);//大于或者等于 m 加上对应的n/i的欧拉函数 }
n最大1000 000 000 TLE必然事件。
可以这样优化一下:
只遍历一半,加上 n/i >= m 的情况(记着i * i == n 的情况不能加)
for(i = 1; i*i <= n; i++)//遍历所有可能的 i { if(n % i)//不能整除 continue; /*只处理n % i == 0 的 i */ if(i >= m) ans += euler(n/i);//大于或者等于 m 加上对应的n/i的欧拉函数 if(n/i >= m && i*i != n) ans += euler(i); }
ac代码:15ms (真快)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int euler(int n)//求n的欧拉函数 { int eu = n; int i; for(i = 2; i*i <= n; i++) { if(n % i == 0) { eu = eu * (i-1) / i; while(n % i == 0) n /= i; } } if(n > 1) eu = eu * (n-1) / n; return eu; } int main() { int t; int n, m; int i; int ans; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); ans = 0; for(i = 1; i*i <= n; i++)//遍历所有可能的 i { if(n % i)//不能整除 continue; /*只处理n % i == 0 的 i */ if(i >= m) ans += euler(n/i);//大于或者等于 m 加上对应的n/i的欧拉函数 if(n/i >= m && i*i != n) ans += euler(i); } printf("%d\n", ans); } return 0; }