diff --git a/TangDou/Topic/Mobius/P4318.cpp b/TangDou/Topic/Mobius/P4318.cpp index 61ddbfc..753b170 100644 --- a/TangDou/Topic/Mobius/P4318.cpp +++ b/TangDou/Topic/Mobius/P4318.cpp @@ -5,7 +5,7 @@ using namespace std; const int N = 100010; // 筛法求莫比乌斯函数(枚举约数) -int mu[N], sum[N]; // sum[N]:梅滕斯函数,也就是莫比乌斯函数的前缀和 +int mu[N]; int primes[N], cnt; bool st[N]; void get_mobius(int n) { @@ -25,14 +25,11 @@ void get_mobius(int n) { mu[t] = -mu[i]; } } - // 维护u(x)前缀和:梅滕斯函数 - for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + mu[i]; } -int check(int g, int k) { +int check(int mid, int k) { int res = 0; - for (int i = 1; i * i <= g; i++) - res = res + mu[i] * (g / i / i); - + for (int i = 1; i * i <= mid; i++) // 枚举范围内每个平方数 + res += mu[i] * (mid / i / i); return res >= k; } @@ -45,13 +42,13 @@ signed main() { while (T--) { cin >> k; // 第k个数 int l = 1, r = 2e9; - while (l <= r) { + while (l < r) { int mid = l + r >> 1; - if (!check(mid, k)) - l = mid + 1; + if (check(mid, k)) + r = mid; else - r = mid - 1; + l = mid + 1; } - cout << r + 1 << endl; + cout << r << endl; } } diff --git a/TangDou/Topic/莫比乌斯函数.md b/TangDou/Topic/莫比乌斯函数.md index 43ece3c..4cb1bd4 100644 --- a/TangDou/Topic/莫比乌斯函数.md +++ b/TangDou/Topic/莫比乌斯函数.md @@ -208,64 +208,59 @@ signed main() { > **注**: 与上一题的区别在于上一题明确给出了最大值$n$,也就是右边界的范围,本题没有告诉我们范围,需要我们自己找到右边界。随着右边界越来越大,肯定符合条件的数字个数也会越来越多,也就是上面说到的单调性。我们可以用二分来假设一个右边界,然后不断的收缩区间来找到准备的右边界:在上道题的基础上加上二分,判断$1$到$mid$是否有$K$个无平方因子的数,以此改变左右边界即可。 ```cpp {.line-numbers} -#include -#define ll long long +#include using namespace std; -int vis[40560],mo[40560],p[4253],n; -void init() -{ - int tot=0,k; - mo[1]=1; - for(int i=2;i<=40559;i++) - { - if(vis[i]==0) - { - p[++tot]=i; - mo[i]=-1; +#define int long long +#define endl "\n" +const int N = 100010; + +// 筛法求莫比乌斯函数(枚举约数) +int mu[N]; +int primes[N], cnt; +bool st[N]; +void get_mobius(int n) { + mu[1] = 1; + for (int i = 2; i <= n; i++) { + if (!st[i]) { + primes[cnt++] = i; + mu[i] = -1; } - for(int j=1;j<=tot&&(k=i*p[j])<=40559;j++) - { - vis[k]=1; - if(i%p[j]!=0)mo[k]=-mo[i]; - else - { - mo[k]=0; + for (int j = 0; primes[j] <= n / i; j++) { + int t = primes[j] * i; + st[t] = true; + if (i % primes[j] == 0) { + mu[t] = 0; break; } + mu[t] = -mu[i]; } } } -bool judge(int x) -{ - ll ans=0;int i; - for(int i=1;i*i<=x;i++) - { - ans+=mo[i]*(x/(i*i)); - } - if(ans>=n)return true; - else return false; +int check(int mid, int k) { + int res = 0; + for (int i = 1; i * i <= mid; i++) // 枚举范围内每个平方数 + res += mu[i] * (mid / i / i); + return res >= k; } -int main() -{ - int t; - ll l,r,mid; - init(); - scanf("%d",&t); - while(t--) - { - scanf("%d",&n); - l=n,r=1644934082; - while(l>1; - if(judge(mid)) - r=mid; - else l=mid+1; - } - printf("%lld\n",r); + +signed main() { + // 获取莫比乌斯函数值 + get_mobius(N - 1); + + int T, k; + cin >> T; // T组测试数据 + while (T--) { + cin >> k; // 第k个数 + int l = 1, r = 2e9; + while (l < r) { + int mid = l + r >> 1; + if (check(mid, k)) + r = mid; + else + l = mid + 1; + } + cout << r << endl; } - return 0; } ```