UVa 12174:Shuffle(滑动窗口)

本文介绍了一个音乐播放器乱序播放功能的问题,通过滑动窗口的方法统计了给定播放记录下,下一次随机排序的可能性数量。文章提供了完整的代码实现。

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

题目链接: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 (1s,n100000) 的播放记录(不一定是从最开始记录的) xi(1xis) ,你的任务是统计下次随机排序所发生的时间有多少种有多少种可能性。例如,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值