题面

之前做过一道很类似的题目 洛谷P4168蒲公英 ,然后看到这题很快就想到了解法,做完这题可以对比一下,真的很像。

题目要求区间内出现次数为正偶数的数字的数量。

数据范围1e5,可以分块。

我们预处理出这么两个数组。

一个是某个数字出现次数的分块前缀和,这个很简单。

一个是sum[ i ][ j ]代表从第i个分块到第j个分块出现次数为正偶数的数字的个数。

这个数组很好维护,只需要枚举左端点分块和右端点分块然后统计数字出现次数即可。

这些代码里有一些细节,可以结合注释理解。

  1. for(int i=1;i<=get_pos(n);i++){
  2. int kin=0;
  3. for(int j=i;j<=get_pos(n);j++){
  4. for(int k=(j-1)*len+1;k<=min(n,j*len);k++){//这里有一些细节
  5. tmp[a[k]]++;
  6. if((tmp[a[k]]&1))//如果这个数加完之后变成了奇数
  7. if(tmp[a[k]]>1)//如果加完之后出现次数大于一,那么这个数就作为正偶数被统计进答案了,要减掉
  8. kin--;
  9. else//否则这个数在加一之前没有被统计过,没有必要更改,这里写个else是因为防止与下面那个else产生冲突
  10. kin+=0;
  11. else//加完之后如果变成了偶数那肯定从奇数变成了正偶数,对答案有贡献
  12. kin++;
  13. }
  14. sum[i][j]=kin;
  15. }
  16. for(int j=1;j<=c;j++)//清空辅助数组
  17. tmp[j]=0;
  18.  
  19. }

接下来处理询问。

对于询问的l,r,算出其所在的分块lb,rb。

若l,r所在分块相同或相邻则暴力计算,时间复杂度n1/2

若l,r所在分块之间相隔至少一个分块,那么先将答案设成这两个分块之间的出现次数为正偶数的数字数量。

然后,计算两边散块内数字对答案的贡献。

情况较多,可结合注释理解。

  1. void get_q(){
  2. ans=0;
  3. for(int i=l;i<=lb*len;i++){
  4. tmp[a[i]]++;
  5. if(tmp[a[i]]&1)//如果这个数在散块中出现次数为奇数
  6. if((tim[rb-1][a[i]]-tim[lb][a[i]])&1)//如果它在中间块中出现次数为奇数,那么它没有被预先统计进答案里,且目前它对答案有贡献
  7. ans++;
  8. else//如果这个数在中间块中出现次数为偶数
  9. if(tim[rb-1][a[i]]-tim[lb][a[i]]>0)//如果这个数在中间块中出现次数为正偶数,那么它已经作为答案被统计过了,现在不符合条件要减掉
  10. ans--;
  11. else//这个数并没有作为答案被统计过
  12. if(tmp[a[i]]>1)//如果这个数在散块中之前已经作为正偶数被统计了,要减掉
  13. ans--;
  14. else//否则并没有影响
  15. ans-=0;
  16. else//这个数在散块中出现次数为偶数
  17. if(tim[rb-1][a[i]]-tim[lb][a[i]]&1)//如果这个数在中间块中出现次数为奇数,那么这个数的出现次数被作为正偶数统计过,要减掉
  18. ans--;
  19. else//否则这个数之前没有算进答案里,要加进去
  20. ans++;
  21. }
  22. for(int i=(rb-1)*len+1;i<=r;i++){//以下分类同上
  23. tmp[a[i]]++;
  24. if(tmp[a[i]]&1)
  25. if((tim[rb-1][a[i]]-tim[lb][a[i]])&1)
  26. ans++;
  27. else
  28. if(tim[rb-1][a[i]]-tim[lb][a[i]]>0)
  29. ans--;
  30. else
  31. if(tmp[a[i]]>1)
  32. ans--;
  33. else
  34. ans-=0;
  35. else
  36. if(tim[rb-1][a[i]]-tim[lb][a[i]]&1)
  37. ans--;
  38. else
  39. ans++;
  40. }
  41. for(int i=l;i<=lb*len;i++)//清空辅助数组
  42. tmp[a[i]]--;
  43. for(int i=(rb-1)*len+1;i<=r;i++)
  44. tmp[a[i]]--;
  45. ans+=sum[lb+1][rb-1];
  46. }

处理单次询问时间复杂度为n1/2,可以通过本题。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int h=100010;
  4. const int b_h=1010;
  5. int n,m,c;
  6. int len;
  7. int a[h];
  8. int sum[b_h][b_h];
  9. int tim[b_h][h];
  10. int tmp[h];
  11. int get_pos(int x){
  12. return (x-1)/len+1;
  13. }
  14. void get_pre(){
  15. for(int i=1;i<=get_pos(n);i++)
  16. for(int j=1;j<=c;j++)
  17. tim[i][j]+=tim[i-1][j];
  18. for(int i=1;i<=get_pos(n);i++){
  19. int kin=0;
  20. for(int j=i;j<=get_pos(n);j++){
  21. for(int k=(j-1)*len+1;k<=min(n,j*len);k++){
  22. tmp[a[k]]++;
  23. if((tmp[a[k]]&1))
  24. if(tmp[a[k]]>1)
  25. kin--;
  26. else
  27. kin+=0;
  28. else
  29. kin++;
  30. }
  31. sum[i][j]=kin;
  32. }
  33. for(int j=1;j<=c;j++)
  34. tmp[j]=0;
  35.  
  36. }
  37. }
  38. int l,r,lb,rb;
  39. int ans;
  40. void get_vio(){
  41. ans=0;
  42. for(int i=l;i<=r;i++){
  43. tmp[a[i]]++;
  44. if((tmp[a[i]]&1))
  45. if(tmp[a[i]]>1)
  46. ans--;
  47. else
  48. ans+=0;
  49. else
  50. ans++;
  51. }
  52. for(int i=l;i<=r;i++)
  53. tmp[a[i]]--;
  54. }
  55. void get_q(){
  56. ans=0;
  57. for(int i=l;i<=lb*len;i++){
  58. tmp[a[i]]++;
  59. if(tmp[a[i]]&1)
  60. if((tim[rb-1][a[i]]-tim[lb][a[i]])&1)
  61. ans++;
  62. else
  63. if(tim[rb-1][a[i]]-tim[lb][a[i]]>0)
  64. ans--;
  65. else
  66. if(tmp[a[i]]>1)
  67. ans--;
  68. else
  69. ans-=0;
  70. else
  71. if(tim[rb-1][a[i]]-tim[lb][a[i]]&1)
  72. ans--;
  73. else
  74. ans++;
  75. }
  76. for(int i=(rb-1)*len+1;i<=r;i++){
  77. tmp[a[i]]++;
  78. if(tmp[a[i]]&1)
  79. if((tim[rb-1][a[i]]-tim[lb][a[i]])&1)
  80. ans++;
  81. else
  82. if(tim[rb-1][a[i]]-tim[lb][a[i]]>0)
  83. ans--;
  84. else
  85. if(tmp[a[i]]>1)
  86. ans--;
  87. else
  88. ans-=0;
  89. else
  90. if(tim[rb-1][a[i]]-tim[lb][a[i]]&1)
  91. ans--;
  92. else
  93. ans++;
  94. }
  95. for(int i=l;i<=lb*len;i++)
  96. tmp[a[i]]--;
  97. for(int i=(rb-1)*len+1;i<=r;i++)
  98. tmp[a[i]]--;
  99. ans+=sum[lb+1][rb-1];
  100. }
  101. int main(){
  102. scanf("%d%d%d",&n,&c,&m);
  103. len=sqrt(n);
  104. for(int i=1;i<=n;i++)
  105. scanf("%d",&a[i]),tim[get_pos(i)][a[i]]++;
  106. get_pre();
  107. int lst=0;
  108. for(int i=1;i<=m;i++){
  109. scanf("%d%d",&l,&r);
  110. l=(l+lst)%n+1,r=(r+lst)%n+1;
  111. if(l>r)
  112. swap(l,r);
  113. lb=get_pos(l),rb=get_pos(r);
  114. if(lb>=rb-1)
  115. get_vio();
  116. else
  117. get_q();
  118. lst=ans;
  119. printf("%d\n",ans);
  120. }
  121. return 0;
  122. }

完整代码

洛谷 P4135 作诗 题解的更多相关文章

  1. 洛谷P4135 作诗 (分块)

    洛谷P4135 作诗 题目描述 神犇SJY虐完HEOI之后给傻×LYD出了一题: SHY是T国的公主,平时的一大爱好是作诗. 由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为N的文章 ...

  2. 洛谷P4135 作诗

    题意:[l,r]之间有多少个数出现了正偶数次.强制在线. 解:第一眼想到莫队,然后发现强制在线...分块吧. 有个很朴素的想法就是蒲公英那题的套路,做每块前缀和的桶. 然后发现这题空间128M,数组大 ...

  3. 洛谷P4135 作诗(不一样的分块)

    题面 给定一个长度为 n n n 的整数序列 A A A ,序列中每个数在 [ 1 , c ] [1,c] [1,c] 范围内.有 m m m 次询问,每次询问查询一个区间 [ l , r ] [l, ...

  4. 洛谷 P4135 作诗

    分块大暴力,跟区间众数基本一样 #pragma GCC optimize(3) #include<cstdio> #include<algorithm> #include< ...

  5. 洛谷 P4135 作诗(分块)

    题目链接 题意:\(n\) 个数,每个数都在 \([1,c]\) 中,\(m\) 次询问,每次问在 \([l,r]\) 中有多少个数出现偶数次.强制在线. \(1 \leq n,m,c \leq 10 ...

  6. 洛谷P2832 行路难 分析+题解代码【玄学最短路】

    洛谷P2832 行路难 分析+题解代码[玄学最短路] 题目背景: 小X来到了山区,领略山林之乐.在他乐以忘忧之时,他突然发现,开学迫在眉睫 题目描述: 山区有n座山.山之间有m条羊肠小道,每条连接两座 ...

  7. 【洛谷P3960】列队题解

    [洛谷P3960]列队题解 题目链接 题意: Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 n×m ...

  8. 洛谷P2312 解方程题解

    洛谷P2312 解方程题解 题目描述 已知多项式方程: \[a_0+a_1x+a_2x^2+\cdots+a_nx^n=0\] 求这个方程在 \([1,m]\) 内的整数解(\(n\) 和 \(m\) ...

  9. 洛谷P1577 切绳子题解

    洛谷P1577 切绳子题解 题目描述 有N条绳子,它们的长度分别为Li.如果从它们中切割出K条长度相同的 绳子,这K条绳子每条最长能有多长?答案保留到小数点后2位(直接舍掉2为后的小数). 输入输出格 ...

随机推荐

  1. 【java】学习路线2-构造、Scanner包导入、字符串操作、数组、引用类型

    请先查看前置知识: [JAVA]基础1-字符串.堆.栈.静态与引用类型 https://www.cnblogs.com/remyuu/p/15990274.html import java.util. ...

  2. C# using()的本质

    " 程序世界没有秘密,所有答案都在源码里 " 01.点明观点 C#中,非托管资源使用之后必须释放,而using()是使用非托管资源的最佳方式,可以确保资源在代码块结束之后被正确释放 ...

  3. 给定字符串定义char *a = “I love China!”,读入整数n,输出在进行了a = a + n这个赋值操作以后字符指针a对应的字符串

    include<stdio.h> include<string.h> int main() { const char *a="I love China!"; ...

  4. Windows平台Unity3d播放多路RTMP或RTSP流

    好多开发者在做AR.VR或者教育类产品时,苦于如何在windows平台构建一个稳定且低延迟的RTSP或者RTMP播放器,如果基于Unity3d完全重新开发一个播放器,代价大.而且周期长,不适合快速出产 ...

  5. sys.path的使用场景

    起因 在初学python时,经常遇到找不到某个路径下的文件,或者在博客中找到的代码需要暴露出环境变量(如linux中可以export PYTHONPATH="$PYTHON;/carla/b ...

  6. LIMIT和OFFSET分页性能差!今天来介绍如何高性能分页

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. GreatSQL是MySQL的国产分支版本,使用上与MySQL一致. 前言 之前的大多数人分页采用的都是这样: SELEC ...

  7. flink-cdc同步mysql数据到hive

    本文首发于我的个人博客网站 等待下一个秋-Flink 什么是CDC? CDC是(Change Data Capture 变更数据获取)的简称.核心思想是,监测并捕获数据库的变动(包括数据 或 数据表的 ...

  8. 使用SSH连接Windows Server

    之前发过一篇在Windows Server上启用SSH服务器的文章.最近正好有这个需求,需要使用密钥免密登录服务器,试了一下,发现之前的方法不行了.需要再修正一些文件权限. 需要使用Repair-Au ...

  9. 第一个Django应用 - 第二部分:Django数据库配置,模型和后台

    汇总操作 注:polls为应用名 1.执行命令:python manage.py migrate,生成默认的数据库表等 2.修改应用的models.py文件,添加数据库表模型等 3.INSTALLED ...

  10. [题解] Atcoder ABC 225 H Social Distance 2 生成函数,分治FFT

    题目 首先还没有安排座位的\(m-k\)个人之间是有顺序的,所以先把答案乘上\((m-k)!\),就可以把这些人看作不可区分的. 已经确定的k个人把所有座位分成了k+1段.对于第i段,如果我们能求出这 ...