传送门:GCD
题意:求[1,n],[1,m]gcd为k的对数。
分析:莫比乌斯入反演门题,gcd(x,y)==k等价于gcd(x/k,y/k)==1,求出[1,n][1,m]互质的对数,在减去[1,2][2,1]之类重复的个数即答案。
莫比乌斯反演资料: 贾志鹏线性筛
莫比乌斯反演:46ms
#pragma comment(linker,"/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <limits.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 100000000
#define inf 0x3f3f3f3f
#define eps 1e-6
#define N 1000000
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define PII pair<int,int>
using namespace std;
inline int read()
{
char ch=getchar();int x=,f=;
while(ch>''||ch<''){if(ch=='-')f=-;ch=getchar();}
while(ch<=''&&ch>=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
bool vis[N+];
int mu[N+],prime[N+];
void Moblus()
{
memset(vis,false,sizeof(vis));
mu[]=;
int tot=;
for(int i=;i<=N;i++)
{
if(!vis[i])
{
prime[tot++]=i;
mu[i]=-;
}
for(int j=;j<tot;j++)
{
if(i*prime[j]>N)break;
vis[i*prime[j]]=true;
if(i%prime[j]==)
{
mu[i*prime[j]]=;
break;
}
else
{
mu[i*prime[j]]=-mu[i];
}
}
}
}
int main()
{
int T,a,b,c,d,k,cas=;
Moblus();
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("Case %d: ",cas++);
if(k==)
{
puts("");
continue;
}
b=b/k;d=d/k;
if(b>d)swap(b,d);
LL ans=,res=;
for(int i=;i<=b;i++)
ans+=1LL*mu[i]*(b/i)*(d/i);
for(int i=;i<=b;i++)
res+=1LL*mu[i]*(b/i)*(b/i);
printf("%I64d\n",ans-res/);
}
}
欧拉+容斥:484ms
#include <algorithm>
#include <utility>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
const int N=;
LL euler[N];
int num[N],prime[N][];
void EulerPrime()
{
euler[]=;
for(int i=;i<N;i++)
{
if(!euler[i])
{
for(int j=i;j<N;j+=i)
{
if(!euler[j])euler[j]=j;
euler[j]=euler[j]*(i-)/i;
prime[j][num[j]++]=i;
}
}
euler[i]+=euler[i-];
}
//for(int i=1;i<=20;i++)printf("%d ",num[i]);
}
int sum;
int gcd(int a,int b)
{
return a%b==?b:gcd(b,a%b);
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b;
}
void dfs(int i,int lm,int flag,int n,int m)
{
if(i==num[n])return;
int x=lcm(prime[n][i],lm);
sum+=m/x*flag;
for(int j=i;j<num[n];j++)
dfs(j+,x,-flag,n,m);
}
int solve(int m,int n)
{
sum=;
for(int i=;i<num[n];i++)
{
dfs(i,,,n,m);
}
return sum;
}
int main()
{
int cas=,T;
int a,b,c,d,k;
EulerPrime();
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k==)
{
printf("Case %d: ",cas++);
puts("");continue;
}
if(b>d)swap(b,d);
b/=k;d/=k;LL ans=euler[b];
for(int i=b+;i<=d;i++)
ans+=b-solve(b,i);
printf("Case %d: %I64d\n",cas++,ans);
}
}