前言
板题一号
题目
题意:
求 (sum_{i=a}^bsum_{j=c}^d[gcd(i,j)=k])
讲解
大方向为容斥
令 (S(n,m)=sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=k])
则原式可化为 (S(b,d)-S(a-1,d)-S(b,c-1)+S(a-1,c-1))
令 (f(k)=sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=k]),即 (S(n,m))
(F(k)=sum_{i=1}^nsum_{j=1}^m[k|gcd(i,j)])
(F(k)=sum_{d|k}f(d)=lfloordfrac{n}{k} floorlfloordfrac{m}{k} floor)
(f(k)=sum_{k|d}mu(dfrac{d}{k})F(d)=sum_{k|d}mu(dfrac{d}{k})lfloordfrac{n}{d} floorlfloordfrac{m}{d} floor)
我们将 (dfrac{d}{k}) 换元,得到:
(f(k)=sum_{i=1}^{frac{min(n,m)}{k}}mu(i)lfloordfrac{n}{ik} floorlfloordfrac{m}{ik} floor)
然后数论分块即可
代码
int mu[MAXN],prime[MAXN],pn,s[MAXN];
bool vis[MAXN];
void sieve(int x)
{
s[1] = mu[1] = 1;
for(int i = 2;i <= x;++ i)
{
if(!vis[i]) prime[++pn] = i,mu[i] = -1;
for(int j = 1;j <= pn && i * prime[j] <= x;++ j)
{
vis[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
s[i] = s[i-1] + mu[i];
}
}
int solve(int x,int y)
{
if(x>y) swap(x,y);
int ret = 0;
for(int l = 1,r;l <= x;l = r+1)
{
r = Min(x/(x/l),y/(y/l));
ret += (x / (l*k)) * (y / (l*k)) * (s[r] - s[l-1]);
}
return ret;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
sieve(50000);
for(int T = Read(); T ;-- T)
{
a = Read(); b = Read(); c = Read(); d = Read(); k = Read();
Put(solve(b,d) - solve(a-1,d) - solve(b,c-1) + solve(a-1,c-1),'
');
}
return 0;
}