入门题:hdu 1695
题目大意:求满足x属于区间[1,m]与y属于区间[1,n],且gcd(x,y)=k的数对(x,y)个数。(x,y)与(y,x)属于算作同一个数对。
分析:问题与求x∈[1,m/k],y∈[1,n/k]且gcd(x,y)=1数对(x,y)个数等价。。
设f(i)表示x∈[1,m/k],y∈[1,n/k]且gcd(x,y)=i的数对个数,相应地设F[i]表示x∈[1,m/k],y∈[1,n/k]且gcd(x,y)能被i整除的数对x,y个数。
显然有F[i]=sigma(f[d]) (其中d|i,即d为i的因子)
而F[i]容易求出:F[i]=[a/i][b/i] (a=m/k,b=n/k, []表示向下取整)
于是根据莫比乌斯反演定理,有f[i]=sigma(u[d/i]]*F[d]) 其中i|d
要求的值为f[1]=sigma(u[d]*F[d])
#include <stdio.h>
#define N 100005
typedef long long LL;
int min(int a,int b) {return a<b?a:b;}
int u[N],p[N],v[N];
void init()
{
int i,j,t=0;
u[1]=1;
for(i=2;i<N;++i)
{
if(!v[i]) p[t++]=i,u[i]=-1;
for(j=0;j<t&&p[j]*i<N;++j)
{
v[p[j]*i]=1;
if(i%p[j]==0) {u[p[j]*i]=0;break;}
u[i*p[j]]=-u[i];
}
}
}
int main()
{
int ca,n,i,t,a,b,c,d,k;
LL ans,tmp;
init();
scanf("%d",&n);
for(ca=1;ca<=n;++ca)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(!k) {printf("Case %d: 0\n",ca);continue;} //注意k=0的时候
tmp=ans=0;
b/=k,d/=k;
t=min(b,d);
for(i=1;i<=t;++i) {tmp+=(LL)u[i]*(t/i)*(t/i);ans+=(LL)u[i]*(b/i)*(d/i);}
ans-=tmp/2;
printf("Case %d: %lld\n",ca,ans);
}
return 0;
}
另外还有bzoj 2301和这题差不多,在资料里面已经分析了。用到了分块加速