題目連結:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=844&page=show_problem&problem=3326
題意:你正在使用的音樂播放器有一個所謂的亂序播放功能,即隨機打亂歌曲的播放順序。假設一共有s首歌,則一開始會給這s首歌隨機排序,全部播放完畢後再重新隨機排序、繼續播放,依次類推。注意,當s首歌播放完畢之前不會重新排序。這樣,播放記錄裡的每s首歌都是1~s的一個排列。給出一個長度為n (1≤s,n≤100000) (1 \le s, n \le 100000)的播放記錄(不一定是從最開始記錄的) xi(1≤xi≤s) x_i(1 \le x_i \le s),你的任務是統計下次隨機排序所發生的時間有多少種有多少種可能性。例如,s=4,播放記錄是3,4,4,1,3,2,1,2,3,4,不難發現只有一種可能性:前兩首是一個段的最後兩首歌,後面是兩個完整的段,因此答案是1;當s=3時,播放記錄1,2,1有兩種可能:第一首是一個段,後兩首是另一段;前兩首是一段,最後一首是另一段。答案為2。(本段摘自《演算法競賽入門經典(第2版)》)
分析:
滑動視窗的思想,維護長度為s的視窗看是否合法,最後枚舉可能答案進行判斷即可。
代碼:
這#include <fstream>#include <iostream>#include <cstring>#include <algorithm>#include <stack>#include <sstream>#include <string>#include <map>#include <cmath>#include <queue>#include <vector>#include <set>#include <string>#include <vector>using namespace std;const int maxn = 100000 + 5;int T, ans, cnt, s, n;int a[maxn * 3], num[maxn], x[maxn * 2];bool flag;int main(){ scanf("%d", &T); for (int C = 0; C < T; ++C) { ans = 0; memset(a, -1, sizeof(a)); memset(x, 0, sizeof(x)); memset(num, 0, sizeof(num)); scanf("%d%d", &s, &n); cnt = s; for (int i = s; i < s + n; ++i) scanf("%d", &a[i]); for (int i = s; i < s + s + n; ++i) { if (a[i - s] != -1) { --num[a[i - s]]; if (num[a[i - s]] == 0) --cnt; } else --cnt; if (a[i] != -1) { ++num[a[i]]; if (num[a[i]] == 1) ++cnt; } else ++cnt; if (cnt == s) x[i - s] = 1; } for (int i = 0; i < s; ++i) { flag = true; for (int j = i; j < s + n; j += s) if (!x[j]) { flag = false; break; } if (flag) ++ans; } printf("%d\n", ans); } return 0;}