天天看點

UVa 12174 Shuffle(滑動視窗)

https://vjudge.net/problem/UVA-12174      

題意:

你在聽音樂播放器,它采用随機播放形式。随機播放的原理時先随機産生一個1~n的排列,然後就按這個排列順序播放歌曲。播放完這序列的所有歌曲以後,再次随機生成一個1~n的排列,再繼續播放。

現在給你一個播放曆史記錄,這個曆史記錄是不完整的,以為它是開始記錄時,已經有些歌曲播放過了而沒有記錄到。

現在給你一段從某個時刻開始的播放音樂的曆史記錄,以及播放器裡一共有多少首歌。

問曆史記錄中第一首歌可能是某個随機清單中的第幾首,總共有多少種可能?

思路:

滑動視窗,依次周遊,檢查每個數能否作為循環的開始。

1 #include<iostream> 
 2 #include<cstring>
 3 #include<set>
 4 using namespace std;
 5 
 6 const int N = 1e5 + 5;
 7 
 8 int s, n, a[N], vis[N];
 9 bool flag[N];
10 int ans;
11 
12 void init() {
13     cin >> s >> n;
14     int num = 0;
15     for (int i = 0; i < n; i++) {
16         cin >> a[i];
17         if (i < s) {   //對前面的s個進行分析
18             if (vis[a[i]]) num++;   //統計前s個中重複的數字
19             vis[a[i]]++;
20         }
21     }
22 
23     for (int i = 0; i < n; i++) {
24         //如果num=0,說明前s個中沒有重複的數字,那麼第一個數字可以作為循環的開始
25         if (num == 0) flag[i] = true;
26 
27         //視窗開始滑動
28         if (vis[a[i]] == 2) num--;    //如果此時最左邊的數為重複了的數,num需要減1
29         vis[a[i]]--;
30 
31         int k = i + s;     //新數字進入滑動視窗
32         if (k >= n) continue;
33         if (vis[a[k]]) num++;   //如果已經出現過
34         vis[a[k]]++;
35     }
36 }
37 
38 bool judge(int x) {   
39     for (int i = x; i < n; i += s)
40         if (!flag[i]) return false;
41     return true;
42 }
43 
44 void solve() {
45     memset(vis, 0, sizeof(vis));
46 
47     ans = 0;
48     for (int i = 0; i < s; i++) {
49         if (judge(i)) ans++;
50         if (i >= n) continue;
51         //從左往右依次周遊,如果目前a[i]前面已經出現過,那麼前面必須會有開頭,此時必須結束循環
52         if (vis[a[i]]) break;
53         vis[a[i]]++;
54     }
55 }
56 
57 int main() {
58     //freopen("D:\\txt.txt", "r", stdin);
59     int t;
60     cin >> t;
61     while (t--) {
62         memset(flag, 0, sizeof(flag));
63         memset(vis, 0, sizeof(vis));
64         init();
65         solve();
66         cout << ans << endl;
67     }
68     return 0;
69 }      
1 #include<iostream> 
 2 #include<cstring>
 3 #include<set>
 4 using namespace std;
 5 
 6 const int maxn = 100000 + 5;
 7 int a[maxn];
 8 int vis[maxn],flag[maxn];
 9 
10 int s, n, ans;
11 
12 bool judge(int x)
13 {
14     for (int i = x; i < n; i += s)
15     if (!flag[i]) return false;
16     return true;
17 }
18 
19 int main() {
20     //freopen("D:\\txt.txt", "r", stdin);
21     int t;
22     cin >> t;
23     while (t--) 
24     {
25         memset(flag, 0, sizeof(flag));
26         cin >> s >> n;
27         for (int i = 0; i < n; i++)
28         {
29             cin >> a[i];
30         }
31         for (int i = 0; i < n; i++)
32         {
33             int ok = 0;
34             memset(vis, 0, sizeof(vis));
35             for (int j = i; j < i + s && j < n; j++)
36             { 
37                 if (vis[a[j]])    break;
38                 vis[a[j]] = 1;
39                 if (j == i + s - 1 || j==n-1)    ok = 1;
40             }
41             if (ok)     flag[i] = 1;
42         }
43         ans = 0;
44         memset(vis, 0, sizeof(vis));
45         for (int i = 0; i < s; i++)
46         {
47             if (judge(i))    ans++;
48             if (i >= n)    continue;
49             if (vis[a[i]])    break;
50             vis[a[i]] = 1;
51         }
52         cout << ans << endl;
53     }
54     return 0;
55 }