HDU1695 GCD 懵逼乌斯反演经典题qwq

题目链接:传送门

题目大意:
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. 1xb,1yd,gcd(x,y)==k.
注意 ( x , y ) (x,y) (x,y) ( y , x ) (y,x) (y,x)算同一对,计算答案时只统计一次。

先吐个槽:
题目中说的是 a &lt; = x &lt; = b , c &lt; = x &lt; = d a&lt;=x&lt;=b,c&lt;=x&lt;=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)=Σndf(d).
所以 f ( n ) = Σ n ∣ d μ ( d n ) F ( d ) . f(n)=\Large\Sigma\large_{n|d}\mu(\frac{d}{n})F(d). f(n)=Σndμ(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)=xbxd
所以 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)=Σnkμ(nk)kbkd.(为了避免混淆,我把原来的一些 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)iNiM

然后考虑怎么排除重复的情况:
这里以样例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 inim,所以若 x , y x,y x,y中有一个 &gt; m i n ( b , d ) &gt;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(Tkn)的( 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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值