BZOJ1011 莫比乌斯反演(基础题
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=1101
【题目大意】
求[1,n][1,m]内gcd=k的情况
【题解】
考虑求[1,n][1,m]里gcd=k
等价于[1,n/k][1,m/k]里gcd=1
考虑求[1,n][1,m]里gcd=1
结果为sum(mu[d]*(n/d)*(m/d))
预处理O(n^1.5)
由于n/d只有sqrt(n)种取值,所以可以预处理出miu[]的前缀和 询问时分段求和
【代码】
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 1e5 + 5; int t; //线性筛法求莫比乌斯函数 bool vis[N + 10]; int pri[N + 10]; int mu[N + 10]; int sum[N]; void mus() { memset(vis, 0, sizeof(vis)); mu[1] = 1; int tot = 0; for (int i = 2; i < N; i++) { if (!vis[i]) { pri[tot++] = i; mu[i] = -1; } for (int j = 0; j < tot && i * pri[j] < N; j++) { vis[i * pri[j]] = 1; if (i % pri[j] == 0) { mu[i * pri[j]] = 0; break; } else mu[i * pri[j]] = -mu[i]; } } sum[1]=1; for(int i=2;i<N;i++) sum[i]=sum[i-1]+mu[i]; } int n,m,k; ll cal(int x,int y){ int ma=min(x,y); ll ans=0; for(int i=1,j;i<=ma;i=j+1){ j=min(x/(x/i),y/(y/i)); if(j>=ma) j=ma; ans+=(sum[j]-sum[i-1])*(x/i)*(y/i);//此区间内x/i与y/i均为定值 } return ans; } int main() { mus(); scanf("%d",&t); for(int i=0;i<t;i++){ cin>>n>>m>>k; cout<<cal(n/k,m/k)<<endl; } return 0; }