题目描述

LYK喜欢听音乐,总共有n首音乐,有m个时刻,每个时刻LYK会听其中一首音乐,第i个时刻会听第ai首音乐。它给自己定了一个规定,就是从听音乐开始,听的每连续n首音乐都是互不相同的。例如当n=3时,从听歌开始,123321就是一个合法的顺序(此时LYK听了两轮歌,分别是123和321,每一轮的歌都是互不相同的),而121323就是一个不合法的顺序(LYK也听了两轮歌,第一轮中121存在听了两次相同的歌)。我们现在只截取其中一个片段,也就是说并不知道LYK之前已经听了什么歌。因此121323也仍然可以是一个合法的顺序,因为LYK之前可能听过3,然后再听121323,此时LYK听了三轮歌,分别是312,132和3。

现在LYK将告诉你这m个时刻它听的是哪首歌。你需要求出LYK在听这m首歌之前可能听过的歌的不同方案总数(我们认为方案不同当且仅当之前听过的歌的数量不同)。LYK向你保证它之前听过的歌的数量是在0~n-1之间的。因此你输出的答案也应当是0~n中的某个整数(答案是0表示LYK记错了,没有一个合法的方案)。

输入格式(music.in)

第一行两个数n,m。

第二行m个数表示ai。

输出格式(music.out)

一个数表示答案。

输入样例1

4 10

3 4 4 1 3 2 1 2 3 4

输出样例1

1

样例解释1:LYK之前一定只听过2首歌(12或者21),这样可以分成3部分分别是34,4132,1234,每一部分都没有出现相同的歌。对于其它情况均不满足条件。

输入样例2

6 6

6 5 4 3 2 1

输出样例2

6

样例解释2:LYK之前听过0~5首歌的任意几首都是有可能满足条件的。

数据范围

对于50%的数据n,m<=1000。

对于100%的数据1<=n,m<=100000,1<=ai<=n。

其中均匀分布着n<m以及n>=m的情况。

提示:

LYK知道这个题目很长,但为了便于理解已经加了很多注释了……建议没看懂的同学们再重新看一遍……

分析:比较有意思的一道题,首先我们最多将序列分成m/n + 2段,那么我们花O(n)的时间枚举最前面一段,再花O(m/n + 2)的时间枚举中间段,如果能够做到O(1)查询,那么复杂度就是O(n + m).

考虑怎么O(1)查询,当然边枚举边处理肯定是不行的,我们需要预处理.每次维护一个长度为n的区间[l,r],每次移动区间:r++,l++,同时v2[a[r]]++,v2[a[l]]--,最后有没有v2等于2的,事实上就是一个动态维护.记录下当前左端点是否可行即可.对于最前面和最后面的区间我们分别记录一个前缀和一个后缀就可以了.最后枚举要分多少段,在维护后缀的时候同时扫一下看看能不能满足要求即可.

如果我们把算法看做是一个又一个操作的和,那么我们看看能优化哪些操作的复杂度,比如本题的操作就有枚举操作和查询操作,枚举是O(n)不能优化了,尽最大的可能去优化查询操作.

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5.  
  6. using namespace std;
  7.  
  8. int n, m, a[], v[], V[],sum,V2[],ans;
  9.  
  10. bool check(int x)
  11. {
  12. int i;
  13. for (i = x - n + ; i >= ; i -= n)
  14. if (!V2[i])
  15. return false;
  16. i += n;
  17. if (i - > && !V[i - ])
  18. return false;
  19. return true;
  20. }
  21.  
  22. int main()
  23. {
  24. scanf("%d%d", &n, &m);
  25. for (int i = ; i <= m; i++)
  26. scanf("%d", &a[i]);
  27. for (int i = ; i <= min(n, m); i++)
  28. {
  29. v[a[i]]++;
  30. if (v[a[i]] == )
  31. sum++;
  32. if (!sum)
  33. V[i] = ;
  34. }
  35. if (!sum)
  36. V2[] = ;
  37. for (int i = n + ; i <= m; i++)
  38. {
  39. v[a[i]]++;
  40. if (v[a[i]] == )
  41. sum++;
  42. v[a[i - n]]--;
  43. if (v[a[i - n]] == )
  44. sum--;
  45. if (!sum)
  46. V2[i - n + ] = ;
  47. }
  48. memset(v, , sizeof(v));
  49. sum = ;
  50. int i = ;
  51. for (i = m; i >= ; i--)
  52. {
  53. v[a[i]]++;
  54. if (v[a[i]] >= )
  55. break;
  56. }
  57. for (int j = m; j > max(, m - n); j--)
  58. if (i <= j && check(j))
  59. ans++;
  60. if (ans)
  61. printf("%d\n", (n >= m && ans == m ? n : ans));
  62. else
  63. printf("0\n");
  64. return ;
  65. }

清北学堂模拟赛d1t3 听音乐(music)的更多相关文章

  1. 清北学堂模拟赛day7 数字碰撞

    /* clj:水题别人都满分你不是你就完了,所以说水题一定要细心一点,有这么几个细节:①前导零的处理,全是零的时候要特判②换行要注意,不要多大一行,剩下就是水水的模拟了 */ #include< ...

  2. 清北学堂模拟赛d4t1 a

    分析:大模拟,没什么好说的.我在考场上犯了一个超级低级的错误:while (scanf("%s",s + 1)),导致了死循环,血的教训啊,以后要记住了. /* 1.没有发生改变, ...

  3. 清北学堂模拟赛day7 错排问题

    /* 考虑一下已经放回m本书的情况,已经有书的格子不要管他,考虑没有书的格子,不考虑错排有(n-m)!种,在逐步考虑有放回原来位置的情况,已经放出去和已经被占好的格子,不用考虑,剩下全都考虑,设t=x ...

  4. 清北学堂模拟赛day7 石子合并加强版

    /* 注意到合并三堆需要枚举两个端点,其实可以开一个数组记录合并两堆的结果,标程好像用了一个神奇的优化 */ #include<iostream> #include<cstdio&g ...

  5. 清北学堂模拟赛d6t6 棋盘迷宫

    3.棋盘迷宫(boardgame.pas/c/cpp)(boardgame.in/out)时间限制:5s/空间限制:256M[题目描述]小 A 和小 Z 是非常要好的朋友, 而且他们都对迷宫游戏非常有 ...

  6. 清北学堂模拟赛d1t2 火柴棒 (stick)

    题目描述众所周知的是,火柴棒可以拼成各种各样的数字.具体可以看下图: 通过2根火柴棒可以拼出数字“1”,通过5根火柴棒可以拼出数字“2”,以此类推. 现在LYK拥有k根火柴棒,它想将这k根火柴棒恰好用 ...

  7. 清北学堂模拟赛d1t1 位运算1(bit)

    题目描述LYK拥有一个十进制的数N.它赋予了N一个新的意义:将N每一位都拆开来后再加起来就是N所拥有的价值.例如数字123拥有6的价值,数字999拥有27的价值.假设数字N的价值是K,LYK想找到一个 ...

  8. 清北学堂模拟赛d2t6 分糖果(candy)

    题目描述总共有n颗糖果,有3个小朋友分别叫做L,Y,K.每个小朋友想拿到至少k颗糖果,但这三个小朋友有一个共同的特点:对3反感.也就是说,如果某个小朋友拿到3颗,13颗,31颗,333颗这样数量的糖果 ...

  9. 清北学堂模拟赛d2t5 吃东西(eat)

    题目描述一个神秘的村庄里有4家美食店.这四家店分别有A,B,C,D种不同的美食.LYK想在每一家店都吃其中一种美食.每种美食需要吃的时间可能是不一样的.现在给定第1家店A种不同的美食所需要吃的时间a1 ...

随机推荐

  1. RijndaelManaged 加密

    public string Encrypt(string str) { string result = null; if (str == null) { return result; } try { ...

  2. php获得两个字符串公共最大子串的函数

    <?php header("Content-type: text/html; charset=utf-8"); function search($str1,$str2) { ...

  3. [Swift通天遁地]五、高级扩展-(11)图像加载Loading动画效果的自定义和缓存

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  4. 微信小程序连接Java后台

    有人问我小程序怎么连后台,这里直接贴代码 在app.js里 // api request request(url, params) { return new Promise((resolve, rej ...

  5. blockhouses

    题意 : 给你一张图上面" X " 代表墙 , " . " 代表空地 , 让你在空地上放置炮台 , 条件是 不能 让彼此的炮台 可以互相看见 ( 隔着墙就看不见 ...

  6. Spring Web MVC核心架构

    可以查看DispatherServlet中的源代码,就是doDispatch()方法!

  7. 【转】Java 集合系列01之 总体框架

    Java集合是java提供的工具包,包含了常用的数据结构:集合.链表.队列.栈.数组.映射等.Java集合工具包位置是java.util.*Java集合主要可以划分为4个部分:List列表.Set集合 ...

  8. 黑马程序员 关于c# windows窗体关闭时线程未能完全退出问题(专题一)

    <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IO开发S</a> ...

  9. CSS——属性选择器

    属性选择器:通过对标签中属性的选择,控制标签. <!DOCTYPE html> <html> <head> <style> div[class*=&qu ...

  10. css学习笔记---盒模型,布局

    1.外边距叠加 当一个元素出现在另一个元素上面时第一个元素的底边距与第二个元素的上边距发生叠加,元素被包含时也有可能会发生叠加(如果没有内边距和边框),如果一个空元素没有内边距和边框本身也会发生上下边 ...