链接:https://ac.nowcoder.com/acm/contest/1034/A
来源:牛客网
题目描述
在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。
为了简化起见,我们把所有的蒲公英看成一个长度为 n 的序列a1,a2,…,ana_1,a_2,\dots,a_na1,a2,…,an,其中aia_iai为一个正整数,表示第 i 棵蒲公英的种类编号。
而每次询问一个区间 [l,r] ,你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
为了简化起见,我们把所有的蒲公英看成一个长度为 n 的序列a1,a2,…,ana_1,a_2,\dots,a_na1,a2,…,an,其中aia_iai为一个正整数,表示第 i 棵蒲公英的种类编号。
而每次询问一个区间 [l,r] ,你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。
输入描述:
第一行两个整数n,m,表示有 n 株蒲公英,m 次询问。
接下来一行 n 个空格隔开的整数aia_iai,表示蒲公英的种类。
再接下来 m 行每行两个整数l0l_0l0,r0r_0r0,我们令上次询问的结果为 x(如果这是第一次询问,则 x=0)。
令l=(l0+x−1) mod n+1,r=(r0+x−1) mod n+1l=(l_0+x-1) \bmod n+1,r=(r_0+x-1) \bmod n+1l=(l0+x−1)modn+1,r=(r0+x−1)modn+1,如果l>r,则交换l,r。
最终的询问区间为[l,r]。
输出描述:
输出 m 行。
每行一个整数,表示每次询问的结果。
输入
6 3
1 2 3 2 1 2
1 5
3 6
1 5
输出
1
2
1
备注:
1≤n≤40000,1\leq n\leq 40000,1≤n≤40000,
1≤m≤50000,1\leq m\leq 50000,1≤m≤50000,
1≤ai≤1091\leq a_i\leq 10^91≤ai≤109
开始准备用线段树写,写完发现写错了,就上网搜分块写法,觉得很麻烦,但是很有用、、、
sum[i][j]:1-i块内,数值j的数量
p[i][j]:i->j块中众数是哪一个
pos[i]:下标为i的数值归为哪一个块
L[i],R[i]:第i块的起始点以及终止点(认为不需要,只是当时参考的别人代码出现,可以用i*(len-1)+1,i*len代替)
1)需要注意的就是对于区间众数的求解代码。并不是用tong[]扫一遍然后之间遍历数组tong[],找最大值,
而是边统计边比较,tong[arr[i]]++;if(………………)…………;
2)在pos[r]-pos[r]>=2时,先取出整区间的众数,然后边统计,边比较,与1)中做法一样
AC代码
1 #include <map> 2 #include <cstdio> 3 #include <cmath> 4 #include <cstring> 5 #include <algorithm> 6 #define Inf 0x3f3f3f3f 7 using namespace std; 8 9 map<int,int>ys; 10 const int N = 40005,M=205; 11 int n,m,cnt; 12 int arr[N],tep[N],sum[M][N],p[M][M],pos[N],L[M],R[M],tong[N]; 13 14 void Init(void){ 15 int len = sqrt(1.0 * n); 16 17 int num; 18 for(int i=1;i*len<=n;i++){ 19 L[i]=(i-1)*len+1; 20 R[i]=i*len; 21 for(int j=L[i];j<=R[i];j++){ 22 sum[i][arr[j]]++; 23 pos[j]=i; 24 } 25 num=i; 26 } 27 num++; 28 L[num]=len*(num-1)+1,R[num]=n; 29 for(int i=L[num];i<=n;i++){ 30 pos[i]=num; 31 sum[num][arr[i]]++; 32 } 33 34 for(int i=1;i<=num;i++) 35 for(int j=1;j<=cnt;j++) 36 sum[i][j]+=sum[i-1][j]; 37 38 int col,tot,kth; 39 for(int i=1;i<=num;i++){ 40 tot=0,col=Inf; 41 for(int j=L[i];j<=n;j++){ 42 kth=pos[j]; 43 tong[arr[j]]++; 44 if(tong[arr[j]]>tot || (tong[arr[j]]==tot && col > arr[j])) 45 tot=tong[arr[j]],col=arr[j]; 46 p[i][kth]=col; 47 } 48 for(int j=L[i];j<=n;j++) 49 tong[arr[j]]=0; 50 } 51 } 52 int query(int l,int r){ 53 memset(tong,0,sizeof(tong)); 54 55 int answer,tot; 56 if(pos[r]-pos[l]<=1){ 57 answer=Inf,tot=0; 58 for(int i=l;i<=r;i++){ 59 tong[arr[i]]++; 60 if(tong[arr[i]]>tot || (tong[arr[i]]==tot && answer>arr[i])) 61 tot=tong[arr[i]],answer=arr[i]; 62 } 63 return answer; 64 } 65 66 int p1=pos[l],p2=pos[r]; 67 answer=p[p1+1][p2-1]; 68 tot=sum[p2-1][answer]-sum[p1][answer]; 69 70 int x=l,y=R[p1];//error 71 for(int i=x;i<=y;i++){ 72 tong[arr[i]]++; 73 if(tong[arr[i]]+sum[p2-1][arr[i]]-sum[p1][arr[i]]>tot ||(tong[arr[i]]+sum[p2-1][arr[i]]-sum[p1][arr[i]]==tot && answer>arr[i])) 74 answer=arr[i],tot=tong[arr[i]]+sum[p2-1][arr[i]]-sum[p1][arr[i]]; 75 } 76 77 x=L[p2],y=r; 78 for(int i=x;i<=y;i++){ 79 tong[arr[i]]++; 80 if(tong[arr[i]]+sum[p2-1][arr[i]]-sum[p1][arr[i]]>tot ||(tong[arr[i]]+sum[p2-1][arr[i]]-sum[p1][arr[i]]==tot && answer>arr[i])) 81 answer=arr[i],tot=tong[arr[i]]+sum[p2-1][arr[i]]-sum[p1][arr[i]]; 82 } 83 return answer; 84 } 85 86 int main(void) 87 { 88 scanf("%d%d",&n,&m); 89 for(int i=1;i<=n;i++){ 90 scanf("%d",&arr[i]); 91 tep[i]=arr[i]; 92 } 93 94 sort(tep+1,tep+1+n); 95 cnt = unique(tep+1,tep+1+n)-tep-1; 96 int d; 97 for(int i=1;i<=n;i++){ 98 d=arr[i]; 99 arr[i]=lower_bound(tep+1,tep+1+cnt,arr[i])-tep; 100 ys[arr[i]]=d; 101 } 102 103 Init(); 104 105 int l,r,x=0; 106 for(int i=1;i<=m;i++){ 107 scanf("%d%d",&l,&r); 108 l=(l+x-1)%n+1; 109 r=(r+x-1)%n+1; 110 if(l>r) 111 swap(l,r); 112 x=ys[query(l,r)]; 113 printf("%d\n",x); 114 } 115 116 return 0; 117 }