D-The Number of Pairs
传送门
题目大意:
给定
c
,
d
,
x
c,d,x
c,d,x, 找出有多少对正整数对
(
a
,
b
)
(a,b)
(a,b) 满足下述等式:
c
•
l
c
m
(
a
,
b
)
−
d
•
g
c
d
(
a
,
b
)
=
x
c•lcm(a,b)-d•gcd(a,b)=x
c•lcm(a,b)−d•gcd(a,b)=x
解题思路:
c
•
l
c
m
(
a
,
b
)
−
d
•
g
c
d
(
a
,
b
)
=
x
;
l
c
m
(
a
,
b
)
=
a
•
b
g
c
d
(
a
,
b
)
;
c
•
a
•
b
g
c
d
(
a
,
b
)
−
d
•
g
c
d
(
a
,
b
)
=
x
;
c•lcm(a,b)-d•gcd(a,b)=x;\\ lcm(a,b)=\frac{a•b}{gcd(a,b)};\\ \frac{c•a•b}{gcd(a,b)}-d•gcd(a,b)=x;
c•lcm(a,b)−d•gcd(a,b)=x;lcm(a,b)=gcd(a,b)a•b;gcd(a,b)c•a•b−d•gcd(a,b)=x;
令
g
=
g
c
d
(
a
,
b
)
g = gcd(a,b)
g=gcd(a,b),则有
a
=
k
1
•
g
a=k_1•g
a=k1•g,
b
=
k
2
•
g
b=k_2•g
b=k2•g;
c
•
k
1
•
k
2
•
g
−
d
•
g
=
x
;
g
•
(
c
•
k
1
•
k
2
−
d
)
=
x
;
g
=
x
c
•
k
1
•
k
2
−
d
;
c•k_1•k_2•g-d•g=x;\\ g•(c•k_1•k_2-d)=x;\\ g=\frac{x}{c•k_1•k_2-d};
c•k1•k2•g−d•g=x;g•(c•k1•k2−d)=x;g=c•k1•k2−dx;
其中
g
∈
N
+
g∈N^+
g∈N+,即
(
c
•
k
1
•
k
2
−
d
)
∣
x
;
(c•k_1•k_2-d)\ |\ x;
(c•k1•k2−d) ∣ x; (符号解释:
x
∣
y
x|y
x∣y 指的是
x
x
x 可以整除
y
y
y,即
y
y
y %
x
=
=
0
x==0
x==0)
由此可以想到枚举
x
x
x 的约数来求解;假设其中的一个约数为
y
y
y;
y
=
c
•
k
1
•
k
2
−
d
;
k
1
•
k
2
=
y
+
d
c
;
y=c•k_1•k_2-d;\\ k_1•k_2=\frac{y+d}{c};
y=c•k1•k2−d;k1•k2=cy+d;
在约数
y
y
y 确定的情况下,
g
g
g的值也是确定的,因
a
=
k
1
•
g
a=k_1•g
a=k1•g,
b
=
k
2
•
g
b=k_2•g
b=k2•g,所以
k
1
k_1
k1 与
k
2
k_2
k2 的值和
a
与
b
a与b
a与b的值是一 一对应的,因此可通过计算
(
k
1
,
k
2
)
(k_1,k_2)
(k1,k2)的对数来间接计算
(
a
,
b
)
(a,b)
(a,b)的对数。
g
c
d
(
a
,
b
)
=
g
gcd(a,b)=g
gcd(a,b)=g,
k
1
k_1
k1与
k
2
k_2
k2互质。令
m
=
y
+
d
c
m=\frac{y+d}{c}
m=cy+d ;
问题: 需要求有多少对互质的正整数的乘积是
m
m
m?
算术基本定理:任何一个大于1的自然数
N
N
N, 如果
N
N
N 不为质数,那么
N
N
N 可以唯一分解成有限个质数的乘积。
则
m
m
m 可以表示为:
m
=
p
1
c
1
•
p
2
c
2
•
.
.
.
•
p
n
c
n
m=p_1^{c_1}•p_2^{c_2}•...•p_n^{c_n}
m=p1c1•p2c2•...•pncn
任意两个质数之间是互质的,
1
1
1与任意的正整数都是互质的。
很明显相同的质因子不能同时出现在
k
1
k_1
k1 和
k
2
k_2
k2 中,则可按照质因数种类数将其化分为
n
n
n 类,对于每一类数要么全部放入
k
1
k_1
k1中,要么全部放入
k
2
k_2
k2中。因质数之间互质,固质数的幂之间同样是互质的,所以以这种形式划分是合理的。每一类都有两种选择,一共有
n
n
n类,所以总的方案数为
2
n
2^n
2n种。
综上所述,本题的答案即为:
a
n
s
w
e
r
=
∑
y
∣
x
g
e
t
(
y
)
answer=\displaystyle\sum_{y|x}{get(y)}
answer=y∣x∑get(y).
g
e
t
函
数
get函数
get函数:传入参数
y
y
y ,计算出
y
+
d
c
\frac{y+d}{c}
cy+d的质因子个数
c
n
t
cnt
cnt,返回
2
c
n
t
2^{cnt}
2cnt;
分析一下时间复杂度,线性筛O(n),枚举约数
n
\sqrt{n}
n,t次询问,
g
e
t
get
get函数O(
n
l
o
g
n
\sqrt{\frac{n}{log\ n}}
log nn),总的时间复杂度O(
n
+
t
n+t
n+t•
n
\sqrt{n}
n•
n
l
o
g
n
\sqrt{\frac{n}{log\ n}}
log nn),
t
∈
1
e
4.
n
∈
1
e
7
t∈1e4.n∈1e7
t∈1e4.n∈1e7,很明显时间复杂度很大。接下来考虑优化。
每一个数的质因子个数可以在线性筛中维护,具体维护方法请参考代码。因此get函数即可O(1)的时间复杂度来实现。
总的时间复杂度O(
n
+
t
•
n
n+t•\sqrt{n}
n+t•n),大约是O(4e7),在2s的时间限制内完全可以过掉。
上代码:
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 20000010;
ll c, d, x;
ll prime[N], cnt;
ll vis[N];
void get_prime()
{
for (int i = 2;i < N;i++)
{
if (!vis[i]) prime[cnt++] = i, vis[i] = 1;
for (int j = 0;prime[j] <= N / i;j++)
{
if (i % prime[j] == 0)
{
vis[prime[j] * i] = vis[i];
break;
}
else {
vis[prime[j] * i] = vis[i] + 1;
}
}
}
}
ll qpow(ll a, ll b)
{
ll res = 1;
while (b)
{
if (b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
ll get(ll i)
{
if ((i + d) % c) return 0;
int m = (i + d) / c;
return qpow(2, vis[m]);
}
int main()
{
int t;cin >> t;
get_prime();
while (t--)
{
cin >> c >> d >> x;
ll ans = 0;
for (int i = 1;i <= x / i;i++)
{
if (x % i == 0)
{
ans += get(i);
if (x / i != i) ans += get(x / i);
}
}
cout << ans << endl;
}
return 0;
}