题目描述
给出n个门,第i秒可以向前跳i个门,过了第n个门之后回到第1个门的位置,问i为多少时,可以恰好回到第1个门
样例输入
5
2
4
6
8
10
样例输出
3
7
3
15
4
思路
题目可转化为
求
(
m
+
1
)
m
≡
0
(
m
o
d
2
n
)
(m + 1)m\equiv0(\bmod\ 2n)
(m+1)m≡0(mod 2n)
设
a
∣
2
n
a|2n
a∣2n,则
b
=
2
n
a
b=\frac{2n}{a}
b=a2n
那么
x
+
1
=
a
p
,
x
=
b
q
x + 1 = ap,x=bq
x+1=ap,x=bq,联立可得
a
p
−
b
q
=
1
ap - bq = 1
ap−bq=1
用扩欧求最小解即可
因为要满足
g
c
d
(
a
,
b
)
=
1
gcd(a,b) = 1
gcd(a,b)=1,每次可以看n的质因子分不分给a就好了
加一点优化(比如
m
o
d
\bmod
mod的时候改成减,然后快读快输什么的)
加上就可以过了
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const ll N = 2e6 + 10;
ll pp[N], prime[N], v[N];
ll n, ans, m, t, T;
ll read()
{
ll x = 0, flag = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') flag = -1; ch = getchar();}
while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
return x * flag;
}
void write(ll x)
{
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
return;
}
ll minn(ll a, ll b)
{
if(a > b) return b;
return a;
}
void primes()
{
m = 0;
for(register int i = 2; i <= N; ++i)
{
if(v[i] == 0) {
prime[++m] = i;
v[i] = i;
}
for(int j = 1; j <= m; ++j) {
if(prime[j] > v[i] || prime[j] * i > N)
break;
if(i % prime[j] == 0) break;
v[i * prime[j]] = prime[j];
}
}
}
//线性筛求质数
ll exgcd(ll a, ll b, ll &x, ll& y)
{
if(b == 0) {x = 1; y = 0; return a;}
ll d = exgcd(b, a - (a / b) * b, y, x);
y -= a / b * x;
return d;
}
//扩欧
void dfs(ll a, ll now)
{
if(now == t + 1)
{
ll x, y;
ll b = n / a;
ll d = exgcd(a, b, x, y);
x = -x;
while(x <= 0) x += b;
ans = minn(ans, x * a);
return;
}
dfs(a * pp[now], now + 1);
dfs(a, now + 1);
}
//暴搜每种分质因子的情况求最小值
int main()
{
primes();
T = read();
for(int i = 1; i <= T; ++i)
{
memset(pp, 0, sizeof(pp));
t = 0;
n = read();
n *= 2; ll nn = n;
for(register int j = 1; prime[j] * prime[j] <= nn; ++j)
{
if(nn - (nn / prime[j]) * prime[j] == 0) {
pp[++t] = 1;
while(nn - (nn / prime[j]) * prime[j] == 0)
{
pp[t] *= prime[j];
nn /= prime[j];
}
}
}//质因数分解
if(nn > 1) pp[++t] = nn;
ans = 1e18;
dfs(1, 1);
write(ans);
putchar(10);
}
return 0;
}