19校賽快到了 我這個菜雞連去年的題目都還沒看過 現在趕緊來惡補一下(基於搜索引擎做題) 可惜的是今年新生賽我沒法參加了 要去南京參加機器人比賽
有一說一 獎狀和獎金好誘人啊
PS:本文持續更新 就看我啥時候能寫完了
Probelm K:第k人
題目描述
TT在跟朋友一起做遊戲,
遊戲規則:n個小朋友(從1開始編號)手拉手,從第一個小朋友開始報數,喊出k的小朋友從圈中出去,然後下個小朋友從1開始報數。
當圈中只剩下一個小朋友的時候結束。TT想知道誰會勝出。
輸入
T(T組,T<=10)
T行,每行兩個個數字n,k代表當前有n個小朋友(n<=1000)k如上述(k<=1e5)
輸出
對每組輸出勝出者的編號
樣例輸入
1
5 2
樣例輸出
3
代碼實現
#include<iostream>
using namespace std;
int main()
{
int t,n,i,k,f;
while(cin>>t)
{
while(t--)
{
cin>>n>>k;
for(i=1;i<=n;i++) f=(f+k)%i;
cout<<f+1<<endl;
}
}
return 0;
}
Probelm L:新第k人
題目描述
TT在跟朋友一起做遊戲,
遊戲規則:n個小朋友(從1開始編號)手拉手,從第一個小朋友開始報數,喊出k的小朋友從圈中出去,然後下個小朋友從1開始報數。當圈中只剩下一個小朋友的時候結束。
TT特別喜歡233這個數字,他把遊戲修改爲第233人。即報出233的人要退出遊戲。
由於第233人太好玩了,玩的人越來越多,現在你還會知道誰會勝出嗎?
輸入
T(T組,T<=10000)
T行,每行一個數字n代表當前有n個小朋友(n<=10000);
輸出
對每組輸出勝出者的編號
樣例輸入
1
5
樣例輸出
5
代碼實現
只要把上一題的k改成233就對了
#include<iostream>
using namespace std;
int main()
{
int t,n,i,f;
while(cin>>t)
{
while(t--)
{
cin>>n;
for(i=1;i<=n;i++) f=(f+233)%i;
cout<<f+1<<endl;
}
}
return 0;
}
知識點:K和L都是約瑟夫環
PS:直接暴力據說是在一定優化後有一定的可能會AC,但是我沒成功。
關於約瑟夫環 百度百科就有解釋 代碼是 f=(f+k)%m 具體解析我看着百度那個看了一晚上愣是沒算明白 最後找到一篇比較好的博客
約瑟夫環
約瑟夫環是一個數學的應用問題:已知n個人(以編號1,2,3…n分別表示)圍坐在一張圓桌周圍;從編號爲k的人開始報數,數到m的那個人出列;他的下一個人又從1開始報數,數到m的那個人又出列;依此規律重複下去,直到圓桌周圍的人全部出列。
前幾天,在一篇文章中得知了約瑟夫環的問題。然後,就涉及瞭解決辦法。這個問題,在許多計算機或者關於數據結構的書中都有提及,而其中的解決辦法便是使用循環鏈表——無論這個循環鏈表是使用指針還是數組實現,模擬約瑟夫環的進行,最後得到解決方案。具體方法肯定早有某人披露。但是,令人深感奇妙的還是這個問題的數學解決。在不統計解決過程,即不統計每次都需要出列哪個序號時,就可以應用數學遞推公式,直接得出最後剩下的那個人的序號。
使用數學方式,奇妙是很奇妙,也確實讓人感受到數學的魅力。可是,在我查找如何推導出這個公式的時候,網上的解決方案都是在我覺得很關鍵的地方一筆帶過。“衆所周知”,“顯而易見”,“很簡單的”……諸如此類。我悲劇的鬱悶了。所以在大家都陶醉在“數學真奇妙啊”的飄飄然中時,我惴惴不安。因爲我只感受到了數學帶給我的困惑。
對着網上的推導思考良久,終於茅塞頓開。所以趕緊寫下來,以防以後再次悲劇和鬱悶。並且希望以後看到這篇文章的人,能和我一樣擺脫困惑。
先總結一下約瑟夫環的遞推公式:
f[1]=0; f[i]=(f[i-1]+m)%i; (i>1)
f[1]=1; f[i]=(f[i-1]+m)%i (i>1); if(f[i]==0) f[i]=i;
P(1, m, k)=1 (i = 1); P(i, m, k)=[P(i - 1, m, k ) + m - 1] % i + 1 (i > 1, 此處先減1是爲了讓模i的值不爲0)
那麼這三個公式有什麼不同?
首先可以肯定的是這三個公式都正確。公式1,得到的是以0~n-1標註的最終序號;公式2,3得到的就是正常的1~n的序號;並且公式2和公式3其實是一個意思。下面我們就分別推導三個公式,並且推導的過程中,你也就能明白這三個公式的共同點和不同點。
公式1的推導:——————————
給出一個序列,從0~n-1編號。其中,k代表出列的序號的下一個,即k-1出列。
a 0, 1, …, k-1, k, k+1, …, n-1
那麼,出列的序號是(m-1)%n,k=m%n(這個可真的是顯而易見)。出列k-1後,序列變爲
b 0, 1, …, k-2, k, k+1, …, n-1
然後,我們繼續從n-1後延長這個序列,可以得到
c` 0, 1, …, k-2, k, k+1, …, n-1, n, n+1, …, n+k-2
我們取從k開始直到n+k-2這段序列。其實這段序列可以看作將序列b的0~k-2段移到了b序列的後面。這樣,得到一個新的序列
c k, k+1, …, n-1, n, n+1, …, n+k-2
好了,整個序列c都減除一個k,得到
d 0, 1, …, n-2
c序列中的n-1, n, n+1都減除個k是什麼?這個不需要關心,反正c序列是連續的,我們知道了頭和尾,就能知道d序列是什麼樣的。
這樣你看,從序列a到序列d,就是一個n序列到n-1序列的變化,約瑟夫環可以通過遞推來獲得最終結果。ok,繼續向下。
剩下的就是根據n-1序列遞推到n序列。假設在n-1序列中,也就是序列d中,我們知道了最終剩下的一個序號是x,那麼如果知道了x轉換到序列a中的編號x`,不就是知道了最終的結果了麼?
下面我們就開始推導出序列a中x的序號是什麼。
d->c,這個變換很容易,就是x+k;
c->b,這個變換是網上大家都一帶而過的,也是令我鬱悶的一個關鍵點。從b->c,其實就是0~k-2這段序列轉換爲n~n+k-2這段序列,那麼再翻轉回去,簡單的就是%n,即(x+k)%n。%n以後,k~n-1這段序列值不會發生變化,而n~n+k-2這段序列則變成了0~k-2;這兩段序列合起來,就是序列b。
於是乎,我們就知道了,x`=(x+k)%n。並且,k=m%n,所以x`=(x+m%n)%n=(x+m)%n。公式1就出來了:f[i]=(f[i-1]+m)%i。當然,i=1就是特殊情況了,f[1]=0。這裏還有一個小問題。也許你會迷惑爲什麼x`=(x+m%n)%n=(x+m)%n中的%n變成公式中f[i]=(f[i-1]+m)%i中的%i?其實這個稍微想想就能明瞭。我們%n就是爲了從序列c轉換到序列b——這是在n-1序列轉換成n序列時%n;那麼從n-2轉換到n-1呢?不是要%(n-1)了嗎?所以這個值是變量,不是常量。
好了,這個最後需要注意的就是從一開始,我們將n序列從0~n-1編號,所以依據公式1得出的序號是基於0開始的。