题目链接:传送门
题目大意:
有
T
T
T组询问,每次让你回答有多少对
x
,
y
x,y
x,y使得
1
≤
x
≤
b
,
1
≤
y
≤
d
,
g
c
d
(
x
,
y
)
=
=
k
.
1\leq x\leq b,1\leq y\leq d,gcd(x,y)==k.
1≤x≤b,1≤y≤d,gcd(x,y)==k.
注意
(
x
,
y
)
(x,y)
(x,y)和
(
y
,
x
)
(y,x)
(y,x)算同一对,计算答案时只统计一次。
先吐个槽:
题目中说的是
a
<
=
x
<
=
b
,
c
<
=
x
<
=
d
a<=x<=b,c<=x<=d
a<=x<=b,c<=x<=d且
a
=
c
=
1...
a=c=1...
a=c=1...
a
a
a和
c
c
c不清楚是干什么的……珂能还有加强版qwq?
不会莫比乌斯反演的话珂以看蒟蒻的博客qwq
令
f
(
n
)
f(n)
f(n)表示
g
c
d
(
x
,
y
)
=
=
n
gcd(x,y)==n
gcd(x,y)==n的数对个数,令
F
(
n
)
F(n)
F(n)表示
g
c
d
(
x
,
y
)
gcd(x,y)
gcd(x,y)是
n
n
n的倍数的数对个数。(这是套路)
不难看出
F
(
n
)
=
Σ
n
∣
d
f
(
d
)
.
F(n)=\Large\Sigma\large_{n|d}f(d).
F(n)=Σn∣df(d).
所以
f
(
n
)
=
Σ
n
∣
d
μ
(
d
n
)
F
(
d
)
.
f(n)=\Large\Sigma\large_{n|d}\mu(\frac{d}{n})F(d).
f(n)=Σn∣dμ(nd)F(d).
假设当前范围是
[
1
,
b
]
[1,b]
[1,b]和
[
1
,
d
]
[1,d]
[1,d],那么
[
1
,
b
]
[1,b]
[1,b]能被
x
x
x整除的有
⌊
b
x
⌋
\lfloor\frac{b}{x}\rfloor
⌊xb⌋个,
[
1
,
d
]
[1,d]
[1,d]能被
x
x
x整除的同理。
所以
F
(
x
)
=
⌊
b
x
⌋
⌊
d
x
⌋
\large F(x)=\lfloor \frac{b}{x} \rfloor\lfloor\frac{d}{x}\rfloor
F(x)=⌊xb⌋⌊xd⌋。
所以
f
(
n
)
=
Σ
n
∣
k
μ
(
k
n
)
⌊
b
k
⌋
⌊
d
k
⌋
.
f(n)=\Large\Sigma\large_{n|k}\mu(\frac{k}{n})\lfloor\frac{b}{k}\rfloor\lfloor\frac{d}{k}\rfloor.
f(n)=Σn∣kμ(nk)⌊kb⌋⌊kd⌋.(为了避免混淆,我把原来的一些
d
d
d换成了
k
k
k)
这个式子已经无法再化简了。
如果不考虑排除
(
x
,
y
)
(x,y)
(x,y)和
(
y
,
x
)
(y,x)
(y,x)重复的情况,则答案珂以表示成:
a
n
s
=
Σ
i
=
1
b
Σ
j
=
1
d
[
g
c
d
(
i
,
j
)
=
=
k
]
ans=\Large\Sigma\large_{i=1}^{b}\Large\Sigma\large_{j=1}^{d}[gcd(i,j)==k]
ans=Σi=1bΣj=1d[gcd(i,j)==k]
因为
g
c
d
(
i
,
j
)
=
=
k
gcd(i,j)==k
gcd(i,j)==k就相当于
g
c
d
(
i
k
,
j
k
)
=
=
1
gcd(\frac{i}{k},\frac{j}{k})==1
gcd(ki,kj)==1,
所以
a
n
s
=
Σ
i
=
1
b
/
k
Σ
j
=
1
d
/
k
[
g
c
d
(
i
,
j
)
=
=
1
]
ans=\Large\Sigma\large_{i=1}^{b/k}\Large\Sigma\large_{j=1}^{d/k}[gcd(i,j)==1]
ans=Σi=1b/kΣj=1d/k[gcd(i,j)==1]
=
f
(
1
)
=f(1)
=f(1)
让
N
=
b
/
k
,
M
=
d
/
k
N=b/k,M=d/k
N=b/k,M=d/k,则
a
n
s
=
Σ
μ
(
i
)
⌊
N
i
⌋
⌊
M
i
⌋
ans=\Large\Sigma\large\mu(i)\lfloor\frac{N}{i}\rfloor\lfloor\frac{M}{i}\rfloor
ans=Σμ(i)⌊iN⌋⌊iM⌋。
然后考虑怎么排除重复的情况:
这里以样例1为例,如果不排除重复情况,会输出
12.
12.
12.
12
12
12种情况如下:
(
1
,
1
)
(
1
,
2
)
(
1
,
3
)
(
1
,
4
)
(
1
,
5
)
(1,1)(1,2)(1,3)(1,4)(1,5)
(1,1)(1,2)(1,3)(1,4)(1,5)
(
2
,
1
)
(
2
,
3
)
(
2
,
5
)
(2,1)(2,3)(2,5)
(2,1)(2,3)(2,5)
(
3
,
1
)
(
3
,
2
)
(
3
,
4
)
(
3
,
5
)
(3,1)(3,2)(3,4)(3,5)
(3,1)(3,2)(3,4)(3,5)
发现重复的情况有:
(
1
,
2
)
(1,2)
(1,2)和
(
2
,
1
)
(2,1)
(2,1)重复;
(
1
,
3
)
(1,3)
(1,3)和
(
3
,
1
)
(3,1)
(3,1)重复;
(
2
,
3
)
(2,3)
(2,3)和
(
3
,
2
)
(3,2)
(3,2)重复。
发现重复的数对中
x
,
y
x,y
x,y都是
[
1
,
m
i
n
(
b
,
d
)
]
[1,min(b,d)]
[1,min(b,d)]区间中的qwq
如何证明呢?考虑计算答案的式子:
其中一部分是
⌊
n
i
⌋
⌊
m
i
⌋
\large\lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{i}\rfloor
⌊in⌋⌊im⌋,所以若
x
,
y
x,y
x,y中有一个
>
m
i
n
(
b
,
d
)
>min(b,d)
>min(b,d),那么
(
x
,
y
)
(x,y)
(x,y)一定只会被算一次(珂以结合样例理解一下qwq)
而当
x
,
y
x,y
x,y都在
[
1
,
m
i
n
(
b
,
d
)
]
[1,min(b,d)]
[1,min(b,d)]区间内时,数对
(
x
,
y
)
(x,y)
(x,y)一定被算了两次(也结合样例理解一下qwq)
所以当且仅当
x
,
y
x,y
x,y都在
[
1
,
m
i
n
(
b
,
d
)
]
[1,min(b,d)]
[1,min(b,d)]区间内时,
(
x
,
y
)
(x,y)
(x,y)被算了两次。
那么排除掉这种重复情况就珂以了,具体见代码。
时间复杂度……感觉应该是
O
(
T
⌊
n
k
⌋
)
\large O(T\lfloor\frac{n}{k}\rfloor)
O(T⌊kn⌋)的(
n
=
m
i
n
(
b
,
d
)
n=min(b,d)
n=min(b,d))……
当
k
=
1
k=1
k=1的时候就是
O
(
T
n
)
O(Tn)
O(Tn)……
T
n
Tn
Tn最大为
3
e
8
3e8
3e8……
3
s
3s
3s时限是珂以卡过的……
然而……为什么我只运行了15ms就过了……数据太水了吧……
可能是昨天切了一道YNOI毒瘤题就觉得所有题都要卡常qwq
毒瘤代码
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#define re register int
#define rl register ll
using namespace std;
typedef long long ll;
int read() {
re x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9') {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9') {
x=10*x+ch-'0';
ch=getchar();
}
return x*f;
}
inline void write(int x) {
if(x>9) write(x/10);
putchar(x%10+'0');
}
namespace I_Love {
const int Size=100005;
int tot,p[Size],prime[Size];
bool vis[Size];
void getp(int x) {
//筛莫比乌斯函数
p[1]=1;
for(re i=2; i<=x; i++) {
if(!vis[i]) {
prime[++tot]=i;
p[i]=-1;
}
for(re j=1; j<=tot && i*prime[j]<=x; j++) {
vis[i*prime[j]]=true;
if(i%prime[j]==0) break;
p[i*prime[j]]=-p[i];
}
}
}
void Fujibayashi_Ryou() {
getp(100000);
int T=read();
for(re Case=1; Case<=T; Case++) {
int a=read();
int b=read();
int c=read();
int d=read();
int k=read();
if(!k) {
printf("Case %d: 0\n",Case);
continue;
}
//a=c=1,不用管
b/=k;
d/=k;
ll ans=0;
int n=max(b,d);
int m=min(b,d);
for(re i=1; i<=m; i++) {
ans+=(ll)p[i]*(n/i)*(m/i);
}
ll repeat=0;
for(re i=1; i<=m; i++) {
repeat+=(ll)p[i]*(m/i)*(m/i);
}
//repeat是出现了两次的数对的个数,所以要除以2
printf("Case %d: %lld\n",Case,ans-(repeat>>1ll));
}
}
}
int main() {
I_Love::Fujibayashi_Ryou();
return 0;
}