UVA 12174 Shuffle(滑动窗口)

T*n已经最大已经是10的7次方了,所以这道题虽然暴力枚举前面不完整歌单的情况的思路好想,但是必须用滑动窗口(或者叫尺取法)的技巧来预处理两个数组,这样可以O(n)完成每组数据。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<set>
#include<list>
#include<deque>
#include<vector>
#include<algorithm>
#include<stack>
#include<queue>
#include<cctype>
#include<sstream>
using namespace std;
#define pii pair<int,int>
#define LL long long int
const double eps=1e-10;
const int INF=1000000000;
const int maxn=100000+10;
int T,n,s,a[maxn],t[maxn],ok[maxn],jie[maxn];
void qian()//预处理前面的非完整list,jie[i]==1表示
//最前面那份不完整list能以a[i]结尾
{
    jie[0]=1;
    memset(t,0,sizeof(int)*(s+1));

    for(int i=1; i<s; i++)
    {
        if(i-1>=n||t[a[i-1]]==0)
        {
            if(i-1<n) t[a[i-1]]++;
            jie[i]=1;
        }
        else
        {
            for(int j=i; j<s; j++)
            {
                jie[j]=0;
                return;
            }
        }
    }
}
void gao()//预处理,ok[i]==1表示以i开始的连续s个数可以组成一个list
{
    int num=0;
    memset(t,0,sizeof(int)*(s+1));

    for(int i=0; i<s; i++)
    {
        if(i>=n)//空位
        {
            num++;
            continue;
        }
        if(t[a[i]]==1)
        {
            ok[0]=0;
            t[a[i]]++;
        }
        else
        {
            num++;
            t[a[i]]++;
        }
    }
    if(num==s) ok[0]=1;

    for(int i=1; i<n; i++)
    {
        if(t[a[i-1]]==1) num--;
        t[a[i-1]]--;

        if(i+s-1>=n||t[a[i+s-1]]==0) num++;
        if(i+s-1<n) t[a[i+s-1]]++;

        if(num==s) ok[i]=1;
        else ok[i]=0;
    }
}
int main()
{
    //freopen("in1.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&s,&n);
        memset(ok,-1,sizeof(int)*(n+1));
        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
        }
        int ans=0;
        gao();
        qian();

        for(int i=0; i<s; i++)
        {
            if(jie[i])//最前面的逗号点在i之前
            {
                bool w=1;
                for(int j=i; j<n; j+=s) //以j开始新的list
                {
                    if(ok[j]!=1)
                    {
                        w=0;
                        break;
                    }
                }
                if(w==1) ans++;
            }
            else
            {
                break;
            }
        }

        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-27 12:47:07

UVA 12174 Shuffle(滑动窗口)的相关文章

UVa 12174 Shuffle (滑动窗口)

题意:你正在使用的音乐播放器有一个所谓的乱序播放功能,即随机打乱歌曲的播放顺序.假设一共有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

UVA - 12174 Shuffle (预处理+滑动窗口)

题意:已知歌单中的歌曲数目s,和部分的播放历史,问下一首可能播放的歌曲种数. 分析: 1.按照歌单数目s,将播放历史划分为几部分. 2.将播放历史的n首歌曲之前加上s首歌曲,之后加上s首歌曲,为防止标号重复,分别将其标号为100001 + i和200001 + i. 3.枚举这个新的序列中的每首歌,以s首为区间,区间开头为i,结尾为s + i - 1,若该区间里的数字不唯一,则不可能以该区间为标准划分,排除i%s这一划分可能. 4.判断区间里歌曲唯一的方法,记录每首歌出现次数,进入区间则加1,离

UVA 12174 Shuffle

#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=2000100; const int INF=1<<29; int s,n; int x[maxn]; int cnt[maxn],m[maxn]; int m

UVa 11572 (滑动窗口) Unique Snowflakes

滑动窗口挺有意思的,如果符合条件右端点一直向前走,不符合的话,左端点向前走. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 set<int> Set; 5 6 const int maxn = 1000000 + 10; 7 int a[maxn]; 8 9 int Scan() { //输入外挂 10 int res = 0; 11 char ch; 12 while((ch = getchar()) >= '0

uva 1606 amphiphilic carbon molecules【把缩写写出来,有惊喜】(滑动窗口)——yhx

Shanghai Hypercomputers, the world's largest computer chip manufacturer, has invented a new classof nanoparticles called Amphiphilic Carbon Molecules (ACMs). ACMs are semiconductors. It meansthat they can be either conductors or insulators of electro

Shuffle UVA - 12174 尺取法

题目:题目链接 思路:见紫书,对具体操作方式还不是很理解,代码是从一个题解里看的,以后多回顾下,需要理解 代码: 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 ini

11536 - Smallest Sub-Array(滑动窗口)

该题其实就是lrj讲的滑动窗口的一个小小变形, 只不过这个窗口的大小是可变的 .  具体方法其实和例题Shuffle类似,用首尾两个指针维护窗口,用一个数组cnt记录1~k中每个数字在窗口中出现的次数,用一个变量c记录窗口中只出现了一次的数字的个数 .   这样只要c == k 这就是一个满足条件的答案,取最小答案即可 . 由于每个元素都只插入删除一次,所以时间复杂度为O(n). 该算法还有一个名字叫"取尺法" ,特点是处理一段长度未知的连续区间,通过反复地推进区间的开头和末尾 ,直到

算法设计与优化策略——滑动窗口

"滑动窗口"和上篇博客中介绍的"等价转换"一样也为一种算法优化的思想.同样,下面通过一个例子,来介绍这种思想.唯一的雪花(Unique snowflake,UVa 11572)输入一个长度为n(n<=10^6)的序列A,找到一个尽量长的连续子序列AL~AR,使得该序列中没有相同的元素.在读完题目以后,我们不难有思路.最简单的思路就是,我们可以通过循环的方法,对每一个元素都找出一它为开头的最长序列(没有相同元素).这个方法也能做出来,但似乎有点太麻烦了.下面,我

tcp滑动窗口与拥塞控制

TCP协议作为一个可靠的面向流的传输协议,其可靠性和流量控制由滑动窗口协议保证,而拥塞控制则由控制窗口结合一系列的控制算法实现.一.滑动窗口协议     所谓滑动窗口协议,自己理解有两点:1. "窗口"对应的是一段可以被发送者发送的字节序列,其连续的范围称之为"窗口":2. "滑动"则是指这段"允许发送的范围"是可以随着发送的过程而变化的,方式就是按顺序"滑动".在引入一个例子来说这个协议之前,我觉得很有必