GMOJ 7177 鱼跃龙门 题解
题面
显然是求最小的x 使得
x
×
(
x
+
1
)
2
≡
0
(
m
o
d
n
)
\frac{x \times(x + 1)}{2} \equiv 0 (mod\; n)
2x×(x+1)≡0(modn)
即
x
×
(
x
+
1
)
≡
0
(
m
o
d
2
n
)
x \times (x + 1) \equiv0(mod\;2n)
x×(x+1)≡0(mod2n)
令
d
=
g
c
d
(
x
,
2
n
)
,
x
=
x
1
d
,
2
n
=
n
1
d
.
d=gcd(x,2n),\\x=x_1d,\\2n=n_1d.
d=gcd(x,2n),x=x1d,2n=n1d.
则
x
1
d
×
(
x
1
d
+
1
)
≡
0
(
m
o
d
n
1
d
)
x_1d\times(x_1d+1)\equiv0(mod\;n_1d)
x1d×(x1d+1)≡0(modn1d)
即
x
1
×
(
x
1
d
+
1
)
≡
0
(
m
o
d
n
1
)
x_1\times(x_1d+1)\equiv0(mod\;n_1)
x1×(x1d+1)≡0(modn1)
注意到
g
c
d
(
x
1
,
n
1
)
=
1
gcd(x_1,n_1)=1
gcd(x1,n1)=1
故
x
1
d
+
1
≡
0
(
m
o
d
n
1
)
x_1d+1\equiv0(mod\;n_1)
x1d+1≡0(modn1)
转换形式. 可得
−
x
1
d
+
k
n
1
=
1
-x_1d+kn_1=1
−x1d+kn1=1
视
d
d
d为常量,可用扩展欧几里得算法求得一个小于
0
0
0的
−
x
1
-x_1
−x1
因此最小的
x
=
x
1
d
x=x_1d
x=x1d
枚举
d
d
d即可.
#include <cstdio>
#include <iostream>
#include <cstring>
#define R register
using namespace std;
typedef long long LL;
const LL inf = 1e15;
LL x, yy, T, n, y[200000][2], cntP, cntY, vis[1000100], p[1000000];
LL ans = inf;
inline LL read() {
LL res; char ch = getchar();
for(; ch > '9' || ch < '0'; ch = getchar());
for(res = 0; ch >= '0' && ch <= '9'; res = res * 10 + ch - '0', ch = getchar());
return res;
}
inline LL gcd(LL a, LL b) {return b == 0 ? a : gcd(b, a % b);}
void exgcd(LL a, LL b) {
if(b == 0) {
x = 1, yy = 0;
return ;
}
exgcd(b, a % b);
LL tmp = x;
x = yy;
yy = tmp - a / b * yy;
return ;
}
void check(LL now) {
if(gcd(now, n / now) > 1) return ;
exgcd(now, n / now);
if(x >= 0) x = x % (n / now) - (n / now);
x = -x * now;
ans = min(ans, x);
}
void dfs(int k, LL now) {
if(k > cntY) {
check(now);
return ;
}
LL tmp = now;
for(R int i = 0; i <= y[k][1]; ++i) {
dfs(k + 1, tmp);
tmp /= y[k][0];
}
return ;
}
int main() {
for(register int i = 2; i <= 1000000; ++i) {
if(!vis[i]) p[++cntP] = i;
for(register int j = 1; j <= cntP; ++j) {
int tmp = p[j] * i;
if(tmp > 1000000) break;
vis[tmp] = 1;
if(i % p[j] == 0) break;
}
}
T = read();
for(; T; T--) {
n = read() * 2;
LL tmp = n;
ans = inf;
memset(y, 0, sizeof(y));
cntY = 0;
for(R int i = 1; i <= cntP && p[i] <= tmp; ++i) {
if(tmp % p[i] == 0) {
++cntY;
y[cntY][0] = p[i];
while(tmp % p[i] == 0) {
y[cntY][1] ++;
tmp /= p[i];
}
}
}
if(tmp > 1) y[++cntY][0] = tmp, y[cntY][1] = 1;
dfs(1, n);
printf("%lld\n",ans);
}
return 0;
}