51nod1471 小S的兴趣

Posted SilverNebula

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod1471 小S的兴趣相关的知识,希望对你有一定的参考价值。

 

题目来源: CodeForces
基准时间限制:1.5 秒 空间限制:131072 KB 分值: 320

小S喜欢有趣的事。但是,每个人的兴趣都是独特的。小S热衷于自问自答。有一天,小S想出了一个问题。

有一个包含n个正整数的数组a和针对这个数组的几个问题。这些问题有两种类型:

1.      在数组下标l到r的部分上,将一个单元格循环移动到右端。即以下面方式重新分配数组上的元素。

a[l], a[l+1], ..., a[r-1], a[r] → a[r], a[l], a[l+1], ..., a[r-1].

 

2.      在数组下标l到r的部分上,计算有多少元素的值与k相等。

 

小S很喜欢这个问题并且很快解决了它,你是否能够解决它呢?

Input
第一行包含整数 n (1 ≤ n ≤ 10*5) —数组元素的数量。第二行包含 n 个整数a[1], a[2], ..., a[n] (1 ≤ a[i] ≤ n)。

第三行包含唯一的整数 q (1 ≤ q ≤ 10*5) —问题的数量。接下来的q行包含了这些询问。

因为你需要在线回答这些问题,所以这些问题将会被编码。第一种类型的询问将会以以下形式给出: 1 Li Ri  。第二种类型的询问将会以以下形式给出: 2 Li Ri Ki 。所有输入的数字都是整数,它们满足以下条件:1 ≤ Li,Ri,Ki ≤ n.

为解码输入的问题,你需要按以下转换操作:
li = ((Li + lastans - 1) mod n) + 1; 
ri = ((Ri + lastans - 1) mod n) + 1; 
ki=((Ki + lastans - 1) mod n) + 1.
lastans 是到当前询问为止最后一个第二种类型的询问的答案 (初始, lastans = 0)。如果转换后, li 比 ri  大,你需要交换这两个数字。
Output
对于每一个第二种类型的问题以单独一行输出答案。
Input示例
7
6 6 2 7 4 2 5
7
1 3 6
2 2 4 2
2 2 4 7
2 2 2 5
1 2 6
1 1 4
2 1 7 3
Output示例
2
1
0
0

 

分块 封装 队列

安利隔壁sdfzyhx的Splay解法: http://blog.csdn.net/sdfzyhx/article/details/73655923

 

这个循环操作看上去很麻烦,很难用数据结构直接维护。

考虑分块,每块内维护数列和每个数的出现次数,这样每次循环的时候只需要修改首尾两块。

查询时就暴力统计首尾两块,中间直接查桶即可。

为了防止循环过多导致块严重变形,每次循环的时候把每个中间整块的尾元素移到下一个整块里,这样每块的大小可以保持不变。

 

因为块内操作有点多,写成了封装形式的,看着异常舒心233

块内用循环队列好像比链表省空间?

 

(算错了数组大小,RE了三次)

  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 using namespace std;
  7 const int mxn=100005;
  8 const int N=298;
  9 int read(){
 10     int x=0,f=1;char ch=getchar();
 11     while(ch<0 || ch>9){if(ch==-)f=-1;ch=getchar();}
 12     while(ch>=0 && ch<=9){x=x*10+ch-0;ch=getchar();}
 13     return x*f;
 14 }
 15 int n;
 16 struct chain{
 17     int a[503],hd,tl;
 18     int cnt[mxn];
 19     void init(){hd=1;tl=0;return;}
 20     void add_front(int x){
 21         hd=hd-1;if(hd<0)hd=500;
 22         a[hd]=x;
 23         cnt[x]++;
 24         return;
 25     }
 26     void add_back(int x){
 27         tl=tl+1;if(tl>500)tl=0;
 28         a[tl]=x;
 29         cnt[x]++;
 30         return;
 31     }
 32     void del_front(){
 33         cnt[a[hd]]--;
 34         hd=hd+1;if(hd>500)hd=0;
 35         return;
 36     }
 37     void del_back(){
 38         cnt[a[tl]]--;
 39         tl=tl-1;if(tl<0)tl=500;
 40         return;
 41     }
 42     void rotate(int l,int r){
 43 //        printf("rotate:%d %d\n",l,r);
 44         int st=(hd+l-1)%501,ed=(hd+r-1)%501;
 45 //        printf("st:%d ed:%d\n",st,ed);
 46         int tmp=a[ed];
 47         while(ed!=st){
 48             a[ed]=(ed==0)?a[500]:a[ed-1];
 49             ed--;if(ed<0)ed=500;
 50         }
 51         a[st]=tmp;
 52         return;
 53     }
 54     int calc(int L,int R,int K){
 55         int st=(hd+L-1)%501,ed=(hd+R-1)%501;
 56         int res=(a[st]==K);
 57         while(st^ed){
 58             st=st+1;if(st>500)st=0;
 59             res+=(a[st]==K);
 60         }
 61         return res;
 62     }
 63     int calc_back(int n,int K){
 64 //        printf("cback:n:%d K:%d\n",n,K);
 65         int st=tl-n+1;
 66 //        printf("st:%d tl:%d\n",st,tl);
 67         if(st<0)st+=501;
 68         int res=(a[st]==K);
 69         while(st^tl){
 70             st=st+1;if(st>500)st=0;
 71             if(a[st]==K)res++;
 72         }
 73         return res;
 74     }
 75     int calc_front(int n,int K){
 76         int ed=(hd+n-1)%501;
 77         int st=hd;
 78         int res=(a[st]==K);
 79         while(st^ed){
 80             st=st+1;if(st>500)st=0;
 81             if(a[st]==K)res++;
 82         }
 83         return res;
 84     }
 85     int head(){
 86         return a[hd];
 87     }
 88     int tail(){
 89         return a[tl];
 90     }
 91     void debug(){
 92         printf("debug:\n");
 93         int x=hd;
 94         printf("%d ",a[hd]);
 95         while(x^tl){
 96             x++;if(x>500)x=0;
 97             printf("%d ",a[x]);
 98         }
 99         puts("");
100         return;
101     }
102 }c[N];
103 int a[mxn];
104 int L[N],R[N],sz,block=0;
105 int bl[mxn];
106 int lastans=0;
107 void solve(){
108     int Q=read(),op,ql,qr;
109     while(Q--){
110 //        printf("Q:%d\n",Q);
111         op=read();
112         ql=read();ql=(ql+lastans-1)%n+1;
113         qr=read();qr=(qr+lastans-1)%n+1;
114         if(ql>qr)swap(ql,qr);
115         if(op==1){
116             if(bl[ql]==bl[qr]){
117                 c[bl[ql]].rotate(ql-L[bl[ql]]+1,qr-L[bl[ql]]+1);
118             }
119             else{
120                 for(int i=bl[ql]+1;i<bl[qr];i++){
121                     c[i].add_front(c[i-1].tail());
122                     c[i-1].del_back();
123                 }
124                 c[bl[qr]].add_front(c[bl[qr]-1].tail());
125                 c[bl[qr]-1].del_back();
126                 //
127                 c[bl[qr]].rotate(1,qr-L[bl[qr]]+1+1);
128                 c[bl[ql]].add_back(c[bl[qr]].head()); 
129                 //把最后一个元素转到最前面,再加到最前一块的末尾
130                 c[bl[qr]].del_front();
131                 c[bl[ql]].rotate(ql-L[bl[ql]]+1,R[bl[ql]]-L[bl[ql]]+1);
132             }
133         }
134         else{
135             int K=read();K=(K+lastans-1)%n+1;
136             if(bl[ql]==bl[qr]){
137                 int res=0;
138                 res=c[bl[ql]].calc(ql-L[bl[ql]]+1,qr-L[bl[ql]]+1,K);
139                 printf("%d\n",res);
140                 lastans=res;
141                 continue;
142             }
143             int res=0;
144             for(int i=bl[ql]+1;i<bl[qr];i++){
145                 res+=c[i].cnt[K];
146             }
147 //            c[bl[ql]].debug();
148 //            c[bl[qr]].debug();
149             res+=c[bl[ql]].calc_back(R[bl[ql]]-ql+1,K);
150             res+=c[bl[qr]].calc_front(qr-L[bl[qr]]+1,K);
151             printf("%d\n",res);
152             lastans=res;
153         }
154     }
155     return;
156 }
157 int main(){
158     int i,j;
159     n=read();
160     for(i=1;i<=n;i++)a[i]=read();
161 //    block=min(n,(int)sqrt(n+0.5)+123);
162     block=400;
163     sz=(n-1)/block+1;
164     for(i=1;i<=sz;i++){
165         L[i]=R[i-1]+1;
166         R[i]=block*i;
167         c[i].init();
168     }
169     R[sz]=min(R[sz],n);
170     for(i=1;i<=sz;i++){
171         for(j=L[i];j<=R[i];j++){
172             c[i].add_back(a[j]);
173             bl[j]=i;
174         }
175     }
176     solve();
177     return 0;
178 }

 

以上是关于51nod1471 小S的兴趣的主要内容,如果未能解决你的问题,请参考以下文章

51nod 2485 小b重排字符串

51nod 1831:小C的游戏

51nod 1631 小鲨鱼在51nod小学

51Nod——T 1631 小鲨鱼在51nod小学

51nod1229 序列求和 V2

51nod1693