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 main()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int T;cin>>T;
    while(T--){
        scanf("%d%d",&s,&n);
        REP(i,1,n) scanf("%d",&x[i]);
        MS0(cnt);MS0(m);
        int k=1;
        int ans=0,tag=1;
        REP(i,1,n){
            cnt[x[i]+k*s]++;
            if(cnt[x[i]+k*s]==2) m[k]++,tag=0;
            if(i%s==0) k++;
        }
        if(tag) ans++;
        //REP(i,0,k) cout<<m[i]<<" ";cout<<endl;
        REP(i,2,s){
            int l=i;
            int k=1;
            bool tag=1;
            while(l-1<=n){
                //cout<<l-1<<" ="<<x[l-1]<<" "<<cnt[x[l-1]+(k-1)*s]<<" "<<x[l-1]+(k-1)*s<<endl;
                cnt[x[l-1]+(k-1)*s]++;
                if(cnt[x[l-1]+(k-1)*s]==2) m[k-1]++;
                cnt[x[l-1]+k*s]--;
                if(cnt[x[l-1]+k*s]==1) m[k]--;
                if(m[k-1]) tag=0;
                k++;
                l+=s;
            }
            //cout<<"i="<<i<<" tag="<<tag<<endl;
            //REP(i,0,k-1) cout<<m[i]<<" ";cout<<endl;
            if(m[k-1]) tag=0;
            if(tag) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}
/**
先明确一个事实:n个数字被分成k个s段,空间复杂度k*s<=n+s。
然后就可以划窗了。
一开始空间复杂度估计错误,直接去暴力了...why am I so stupid...
*/

时间: 2024-08-26 12:10:42

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(滑动窗口)

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

UVa 12174 (滑动窗口) Shuffle

首先预处理一下以每个数为结尾的前s个数是否能构成一个1~s的排列. 可以用cnt数组来记录每个数出现的次数和用一个变量记录一共有多少个不同的数出现. 然后枚举每种可能的情况,也就是枚举第一首歌会出现的位置,注意要考虑到不完整的序列. 代码不长,但是那个ok数组写起来有点蛋疼,因为要考虑到不完整序列的存在,改了好久才改对. 1 #include <cstdio> 2 #include <cstring> 3 #include <cassert> 4 5 const int

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

12174 - Shuffle

这道题可以用"滑动窗口"的思想来做,假想一个滑动的窗口,这个窗口的大小是s,划过一个大小为n的区域,但是因为s可能比n大,所以我们不妨不去考虑s和n的大小,直接开出一个足够大的空间s+s+n,用ok[i]表示以i结尾的窗口是否符合要求.如果最后结果ans == n + 1 ,那么这个说明n<s且这n个数没有重复,所以最终答案为s 代码如下: #include<bits/stdc++.h> using namespace std; const int maxn = 10

uva 10710 - Chinese Shuffle(完美洗牌)

题目链接:uva 10710 - Chinese Shuffle 题目大意:给出n张牌,按照顺序排列好,进行n-1次完美洗牌,问是否可以变成原来德序列. 解题思路:根据完美洗牌的性质,于是第x张牌经过p次后德位置有x?2p,于是只需要证明第1张牌最后是否在远处即可. #include <cstdio> #include <cstring> typedef long long ll; ll pow_mod(ll a, ll n, ll mod) { ll ans = 1; while

uva 1156 - Pixel Shuffle(模拟+置换)

题目链接:uva 1156 - Pixel Shuffle 题目大意:给定一个N*N的黑白位图,有7种操作,并且对应在指令后加上'-'即为操作的逆,给定N和一系列操作,(从最后一个开始执行),问说这一套指令需要执行多少次才能形成循环. 解题思路:模拟指令执行后获得一个置换,分解成若干的循环,各个循环长度的最小公倍数即使答案. #include <cstdio> #include <cstring> #include <algorithm> using namespace

UVA - 1156 Pixel Shuffle (置换+模拟)

Description Shuffling the pixels in a bitmap image sometimes yields random looking images. However, by repeating the shuffling enough times, one finally recovers the original images. This should be no surprise, since ``shuffling" means applying a one