题目链接:http://codeforces.com/gym/101982/attachments
题目大意:有区间[a,b]和区间[c,d],求gcd(x,y)=1,其中x属于[a,b],y属于[c,d],求这样的x,y有多少对。
解题思路:
第一种反演思路:
把下界变换一下
代码:
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int maxn=1e7+7; ll a,b,c,d,mu[maxn],sum[maxn],prime[maxn],tot; void getMobius(int N){ for(int i=1;i<=N;i++) prime[i]=1; mu[1]=1; tot=0; for(int i=2;i<=N;i++){ if(prime[i]){ prime[tot++]=i; mu[i]=-1; } for(int j=0;j<tot&&prime[j]*i<=N;j++){ prime[prime[j]*i]=0; if(i%prime[j]==0){ mu[i*prime[j]]=0; break; } mu[i*prime[j]]=-mu[i]; } } } int main() { scanf("%lld%lld%lld%lld",&a,&b,&c,&d); getMobius(1e7); ll ans=0; for(int i=1;i<=min(b,d);i++) ans+=mu[i]*(b/i-(a-1)/i)*(d/i-(c-1)/i); printf("%lld ",ans); return 0; }
第二种反演思路:
右边全部都是已知的,枚举下可取范围内的d(也就是原来n的倍数,这里n是1)
可以利用容斥原理,先求出[1,b]和[1,d],再减去[1,a-1]和[1,d]以及[1,b]和[1,c-1],最后加上多减的部分[1,a-1]和[1,c-1]。
并且很显然,推演最后得到的式子是可以经过整除分块优化的,只需要预处理出莫比乌斯函数的前缀和即可。
代码:
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int maxn=1e7+7; ll a,b,c,d,mu[maxn],sum[maxn],prime[maxn],tot; void getMobius(int N){ for(int i=1;i<=N;i++) prime[i]=1; mu[1]=1; tot=0; for(int i=2;i<=N;i++){ if(prime[i]){ prime[tot++]=i; mu[i]=-1; } for(int j=0;j<tot&&prime[j]*i<=N;j++){ prime[prime[j]*i]=0; if(i%prime[j]==0){ mu[i*prime[j]]=0; break; } mu[i*prime[j]]=-mu[i]; } } } ll solve(ll n,ll m){ ll res=0; for(ll l=1,r=0;l<=min(n,m);l=r+1){ r=min(n/(n/l),m/(m/l)); res+=(sum[r]-sum[l-1])*(n/l)*(m/l); } return res; } int main() { scanf("%lld%lld%lld%lld",&a,&b,&c,&d); getMobius(1e7); sum[1]=1; for(int i=2;i<=1e7;i++) sum[i]=sum[i-1]+mu[i]; printf("%lld ",solve(b,d)-solve(a-1,d)-solve(c-1,b)+solve(a-1,c-1)); return 0; }