範例程式碼已於UVA
、瘋狂程設(CPE)
、ZeroJudge
上皆測試通過。
在 UVA
上若使用 Python
提交,這題有機率會超時,若遇到 TLE 可以多試幾次,或改成使用 C++
提交。
題意
這是一道關於使用 中值平方法(middle-square-method) 生成偽隨機數的問題。中值平方法是一種由John von Neumann在1946年提出的產生偽隨機數的方法。其運作原理如下:
- 選擇一個初始值 a0,其十進位表示的長度至多為 n 位數。在本題中,使用 n=4。
- 將 a0 自乘,並在前面補上零直到達到 2×n 位數,然後取中間的 n 位數來形成 a1。
- 對於每個 i>0,重複這個過程以生成 ai。
例如:
- 初始值 a0=5555,a02=30858025,中間的4位數是 a1=8580。
- 初始值 a0=1111,a02=01234321,中間的4位數是 a1=2343。
給定初始化值 a0,檢查能生成多少個 不同 的數字。
思路:模擬(Simulation)
由於在遇到重複的數字 ai 後,後續的數字都會重複,因此我們可以使用一個陣列 visited 來標記是否已經出現過該數字,當遇到重複的數字時,即可結束模擬。由於 4 位數的數字最多有 10000 種,因此可以使用一個長度為 10000 的陣列來標記是否出現過該數字。
令 ans 表示不同的數字數量,初始值為 0。當遇到一個新的數字時,ans 加一,並標記該數字已經出現過。由於要取出中間的 4 位數,我們可以使用 ai+1=⌊100(ai2)⌋mod10000 來計算下一個數字。在遇到重複的數字時,即可結束模擬,並輸出不同的數字數量。
複雜度分析
- 時間複雜度:O(10n) ,其中 n 為中間的位數,本題中 n=4,最多需要遍歷 10n 個數字。
- 空間複雜度:O(10n) ,需要一個陣列來標記是否出現過該數字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import sys input = sys.stdin.readline def print(val=""): sys.stdout.write(str(val) + "\n")
while True: n = int(input()) if n == 0: break ans = 0 visited = [False] * 10000 while not visited[n]: ans += 1 visited[n] = True n = (n * n) // 100 % 10000 print(ans)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <bits/stdc++.h> using namespace std; const int N = 10000; #define endl '\n'
bool visited[N];
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); int n; while (cin >> n && n) { int ans = 0; memset(visited, false, sizeof(visited)); while (!visited[n]) { ans++; visited[n] = true; n = (n * n) / 100 % 10000; } cout << ans << endl; } return 0; }
|
寫在最後
Cover photo is remixed from @Ice maker, thanks for their work!