题目链接:传送门
题目大意:
有 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时限是珂以卡过的……
可能是昨天切了一道YNOI毒瘤题就觉得所有题都要卡常qwq
#include
#include
#include
#include
#include
#include
#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;
}