位址
首先,對於經典的約瑟夫環問題,我們記f(n
,m
)f(n,m)
f(n,m)
表示初始有n
nn個人,第m
mm個出隊的人是誰(從0號開始報數)。則有遞推式f(n
,m)=
(f(n
−1,m
−1)+
k)%n
f(n,m)=(f(n-1,m-1)+k)\ \%\ n
f(n,m)
=(f(
n−1,
m−1)
+k)%
n 其中k
kk表示每報數k
kk次乙個人出隊,注意編號從0開始。
遞推式的證明:考慮現在有n
nn個人圍成一圈,然後從0開始報數。假設第乙個出隊的人是x
xx ,這時還有n−1
n-1n−
1個人,我們從剛剛出去的那個人的下乙個人從0重新編號,那麼以當前局面重新開始,第m−1
m-1m−
1個出隊的人是初始所求的同乙個人,但編號不同,差多少呢?即f(n
,m)=
(f(n
−1,m
−1)+
k)%n
f(n,m)=(f(n-1,m-1)+k)\ \%\ n
f(n,m)
=(f(
n−1,
m−1)
+k)%
n 。 +1 -1 細節手玩一下。
回到本題,由於m,k
m,km,
k可能會很大,但不會同時很大,當m
mm較小的時候(m
<=k
m<=k
m<=k
),直接遞推即可。
下面考慮m
>
km>k
m>
k的情況,會發現模數大部分情況下遠大於k
kk,也就是說可以用乘法代替多次加法,這樣可以降低時間複雜度。具體代替多少次呢?考慮f(a
,b)=
an
sf(a,b)=ans
f(a,b)
=ans
, 假設代替x
xx次,則f(a
+x,b
+x)=
ans+
x∗
kf(a+x,b+x) = ans+x*k
f(a+x,
b+x)
=ans
+x∗k
進行取模的等價條件是ans
+x∗k
>=a
+x
ans+x*k > =a+x
ans+x∗
k>=a
+x,即x
>=a
−ans
k−
1x>=\frac
x>=k
−1a−
ans
即代替次數確定了(整除不整除,快加到m
mm了等細節注意一下即可)。
時間複雜度o(感
覺能過)
o(感覺能過)
o(感覺能過
)
#include
using namespace std;
typedef
long
long ll;
const
int maxn=
2e6+10;
ll m,n,k;
ll f[maxn]
;int
main()
else
else
} cout<1<}return0;
}
2018瀋陽現場賽K題題解 約瑟夫問題
題目大意 給定初始人數n,步長m,求第k個被彈出的人的編號。這題有乙個非常重要的條件,那就是sum min m,k 2e6 因此我們可以分情況討論。下面假設編號從0開始。k m 此時k最大為2e6。因此我們可以使用乙個o k 的方法求出答案。設f n,k 為初始為n個人時第k個被彈出的人。第乙個被彈...
2018瀋陽模擬賽 K
這道題很費勁的將所有superme number找了出來,發現317以後就再也沒有該數了 1,2,3,5,7,11,13,17,23,31,37,53,71,73,113,131,137,173,311,317 這個過程過了 很久沒寫字串的題,字串的知識又糊了。輸入一串很長的數,可以用乙個char型...
經典約瑟夫環問題
1 coding utf 8 2 author diva 3 使用者輸入n,n代表人數,圍成一圈,順序排號 4 從第乙個開始報數,1,2,3,數到3的人,退出圈子 5 6 報數邏輯,數到3的把對應的位置置為0,直到剩下最後乙個人 7 def num report list create 8 n 0 ...