Shuffle UVA - 12174

本文介绍了一个关于音乐播放器乱序播放功能的问题解决方法。通过滑动窗口思想,在O(n)的时间复杂度内找出所有可能的播放序列组合。适用于1到10万首歌曲的播放记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送门

题意:你正在使用的音乐播放器有一个所谓的乱序播放功能,即随机打乱歌曲的播放顺序。假设一共有s首歌,则一开始会给这s首歌随机排序,全部播放完毕后再重新随机排序、继续播放,依次类推。注意,当s首歌播放完毕之前不会重新排序。这样,播放记录里的每s首歌都是1~s的一个排列。给出一个长度为n(1≤s,n≤100000)的播放记录(不一定是从最开始记录的)xi(1≤xi≤s),你的任务是统计下次随机排序所发生的时间有多少种有多少种可能性。例如,s=4,播放记录是3,4,4,1,3,2,1,2,3,4,不难发现只有一种可能性:前两首是一个段的最后两首歌,后面是两个完整的段,因此答案是1;当s=3时,播放记录1,2,1有两种可能:第一首是一个段,后两首是另一段;前两首是一段,最后一首是另一段。答案为2。

思路:这个题运用滑动窗口的思想,在O(n)的复杂度下,计算出所有的窗口中是不是有重复的元素,然后最后判断出所有的可行点。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>

#define MAXN 300010
#define MAXE 210
#define INF 10000000
#define MOD 1000000007
#define LL long long
#define pi acos(-1.0)

using namespace std;

int arr[MAXN];
int vis[MAXN];
bool check[MAXN];

int main() {
  std::ios::sync_with_stdio(false);
  int T;
  cin >> T;
  for (int kase = 1; kase <= T; ++kase) {
    memset(arr, -1, sizeof(arr));
    memset(vis, 0, sizeof(vis));
    memset(check, false, sizeof(check));
    int n, m;
    cin >> m >> n;
    for (int i = m; i < n + m; ++i)
      cin >> arr[i];
    int cnt = 0;
    for (int i = m; i < 2 * m + n; ++i) {
      if (arr[i - m] != -1) {
        vis[arr[i - m]]--;
        if (vis[arr[i - m]] == 1)
          cnt--;
      }
      if (arr[i] != -1) {
        vis[arr[i]]++;
        if (vis[arr[i]] > 1)
          cnt++;
      }
      if (cnt == 0) {
        check[i - m] = true;
      }
    }
    int ans = 0;
    for (int i = 0; i < m; ++i) {
      bool flag = true;
      for (int j = i; j < m + n; j += m) {
        if (!check[j]) {
          flag = false;
          break;
        } else {
          check[j] = false;
        }
      }
      if (flag)
        ans++;
    }
    cout << ans << endl;
  }
  return 0;
}

/*
4
4 10
3 4 4 1 3 2 1 2 3 4
6 6
6 5 4 3 2 1
3 5
3 3 1 1 1
7 3
5 7 3
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值