D - Marking
题目链接:D - Marking
官方题解链接:Editorial
题意
给定
N
,
D
,
K
N, D, K
N,D,K
经过的每个格子都会被粉刷 从
i
d
x
=
0
idx = 0
idx=0出发(第一次粉刷第
0
0
0格)
1. 每次向前跳
D
D
D步
(
i
d
x
+
D
)
m
o
d
N
(idx + D) \mod N
(idx+D)modN,若该格子未被粉刷则粉刷,继续执行第
1
1
1步。
2. 若之前被粉刷过则向前一直走
(
i
d
x
+
1
)
m
o
d
N
(idx + 1) \mod N
(idx+1)modN到没粉刷的格子为止,粉刷该格子后回到第
1
1
1步。
问第
K
K
K次粉刷的是哪个格子。
前置知识 (裴蜀定理有关)
首先有 结论: 设
g
=
g
c
d
(
A
,
B
)
g = gcd(A, B)
g=gcd(A,B)
A
=
a
g
A = ag
A=ag,
B
=
b
g
B = bg
B=bg。
a
a
a项式子
0
B
m
o
d
A
0B \mod A
0BmodA,
B
m
o
d
A
B \mod A
BmodA,
2
B
m
o
d
A
2B \mod A
2BmodA,……,
(
a
−
1
)
B
m
o
d
A
(a - 1)B \mod A
(a−1)BmodA。
1.每项式子的值都是
g
g
g的倍数 。
2.且倍数为
0
∼
a
−
1
0 \sim a - 1
0∼a−1每一个数恰好出现一次。
证明:
- B m o d A = B − x A ( x = B / A ) = b g − x a g = ( b − x a ) g B \mod A = B - xA (x = B / A) = bg - xag = (b - xa)g BmodA=B−xA(x=B/A)=bg−xag=(b−xa)g。
- 设有重复的倍数
i
B
m
o
d
A
=
j
B
m
o
d
A
(
i
!
=
j
)
iB \mod A = jB \mod A (i != j)
iBmodA=jBmodA(i!=j)。
i B − j B = ( i − j ) b g = y A iB - jB = (i - j)bg = yA iB−jB=(i−j)bg=yA 为 A A A 的倍数 ( i B − j B ) m o d A = 0 (iB - jB) \mod A = 0 (iB−jB)modA=0 模 A A A 余数相同,那么相减后再模 A A A 余数自然为 0 0 0。
( i − j ) b g = y a g (i - j)bg = yag (i−j)bg=yag
因为 a a a 与 b b b 互质( a a a 与 b b b 若还有大于 1 1 1 的公约数,那么 g c d gcd gcd 就不会是 g g g 而是 g ∗ g c d ( a , b ) g * gcd(a, b) g∗gcd(a,b))。
所以 ( i − j ) (i - j) (i−j) 是 a a a 的倍数 这显然与上式系数区间 [ 0 , a − 1 ] [0, a - 1] [0,a−1]相违背。
解题思路
设
g
=
g
c
d
(
N
,
D
)
g = gcd(N, D)
g=gcd(N,D)
N
=
n
g
N = ng
N=ng,
D
=
d
g
D = dg
D=dg。
对于上述问题有跳跃的前
n
n
n 步为
0
m
o
d
N
0 \mod N
0modN,
D
m
o
d
N
D \mod N
DmodN,
2
D
m
o
d
N
2D \mod N
2DmodN,…… ,
(
n
−
1
)
D
m
o
d
N
(n - 1)D \mod N
(n−1)DmodN。
每一项都是不重复的
g
g
g 的倍数,所以不会触发条件
2
2
2。 而第
n
+
1
n + 1
n+1 步
n
D
m
o
d
N
=
n
d
g
=
d
N
m
o
d
N
=
0
nD \mod N = ndg = dN \mod N = 0
nDmodN=ndg=dNmodN=0。
开始有重复项第二轮开始,此时需要向前走一步
(
0
(0 % N) + 1
(0,接下来又可以按
(
D
m
o
d
N
)
+
1
(D \mod N) + 1
(DmodN)+1,
(
2
D
m
o
d
N
)
+
1
(2D \mod N) + 1
(2DmodN)+1,……的顺序进行
n
n
n 轮跳跃。
每一轮
n
n
n 个直到所有格子都被遍历到。所以我们只需要确定我们在哪一轮,偏移量 + 轮数即可
轮数:
l
e
n
=
(
K
−
1
)
/
n
len = (K - 1) / n
len=(K−1)/n。
偏移量:
a
d
d
=
(
K
−
1
)
m
o
d
n
add = (K - 1) \mod n
add=(K−1)modn。
a
n
s
=
a
d
d
∗
D
ans = add * D % N + len
ans=add∗D。
最初容易想到特殊情况, 当
D
D
D 为
N
N
N 的因子时,前
N
/
D
N / D
N/D 步肯定没有重复,接下来每一步都是上一轮同样倍数 +
1
1
1
若为
0
,
3
,
6
,
9
…
…
0,3,6,9……
0,3,6,9…… 下一轮即为
1
,
4
,
7
,
10
…
…
1,4,7,10……
1,4,7,10……。
随后再引申到非因子的数应该也有一个循环节上进行考虑。
代码
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
inline int gcd(int a, int b){
if(b) while( (a %= b) && (b %= a));
return a + b;
}
void solve()
{
ll N, K, D;
cin >> N >> D >> K;
ll g = gcd(N, D);
ll n = N / g;
ll len = (K - 1) / n;
ll add = (K - 1) % n;
cout << add * D % N + len << "\n";
return ;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)solve();
return 0;
}