2821: 作诗(Poetize)
Time Limit: 50 Sec Memory Limit: 128 MBSubmit: 3526 Solved: 1047
[Submit][Status][Discuss]
Description
神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗。由于时间紧迫,SHY作完诗
之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一
些汉字构成诗。因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次。而且SHY认
为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!)。于是SHY请LYD安排选
法。LYD这种傻×当然不会了,于是向你请教……问题简述:N个数,M组询问,每次问[l,r]中有多少个数出现正偶
数次。
Input
输入第一行三个整数n、c以及m。表示文章字数、汉字的种类数、要选择M次。第二行有n个整数,每个数Ai在[1, c
]间,代表一个编码为Ai的汉字。接下来m行每行两个整数l和r,设上一个询问的答案为ans(第一个询问时ans=0),
令L=(l+ans)mod n+1, R=(r+ans)mod n+1,若L>R,交换L和R,则本次询问为[L,R]。
Output
输出共m行,每行一个整数,第i个数表示SHY第i次能选出的汉字的最多种类数。
Sample Input
5 3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5
Sample Output
2
0
0
0
1
0
0
0
1
HINT
对于100%的数据,1<=n,c,m<=10^5
Source
思路: 数列分块算法
类似bzoj 2724
cnt[i][j]表示前j块里面j出现了几次
num[i][j]表示第i块到第j个块有多少个数出现了偶数次
考虑不完整的两块,即最左边和最右边的两块,先统计这两块里面每个数出现了几次,然后用这些数去原有答案(即中间块)
如果两边某个数出现了奇数次,中间这个数是奇数次,那么ans++
如果两边某个数出现了奇数次,中间这个数是偶数次,那么ans--
如果两边某个数出现了偶数次,中间这个数没有出现过,那么ans++
注意: 这里由于如果按照sqrt(n) 来确定块的大小的化,要超空间,可以让B等于400,这样内存可以卡过去。
时间复杂度O(nsqrt(n))
#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define D(i,a,b) for(int i=a;i>=b;i--)
#define ms(i,a) memset(a,i,sizeof(a))
#define st(x) ( (x-1)*B+1)
#define ed(x) min(x*B,n)
#define bl(x) ( (x-1)/B+1)
int inline read(){
int x=0; char c=getchar();
while (c<'0' || c>'9') c=getchar();
while (c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x;
}
int const maxn=100003;
int cnt[maxn][251],B=400,num[251][251],n,m,a[maxn],t,c[maxn],mx,tmp[maxn];
int query(int l,int r){
int x=bl(l);
int y=bl(r);
int ans=0;
if(x+1<=y-1) ans=num[x+1][y-1];
tmp[0]=0;
if(x==y){
F(i,l,r) {
c[a[i]]++;
if (c[a[i]]==1) tmp[++tmp[0]]=a[i];
if(c[a[i]]>1) {
if(c[a[i]]&1) ans--;
else ans++;
}
}
}else {
int s=l;
int e=ed(x);
F(i,s,e) {
if(!c[a[i]]) tmp[++tmp[0]]=a[i];
c[a[i]]++;
}
s=st(y);
e=r;
F(i,s,e) {
if(!c[a[i]]) tmp[++tmp[0]]=a[i];
c[a[i]]++;
}
F(i,1,tmp[0]){
int x1=c[tmp[i]] & 1;
int x2=cnt[tmp[i]][y-1]-cnt[tmp[i]][x];
if(x1 && x2 && (x2&1)) ans++;
if(x1 && x2 && !(x2&1)) ans--;
if(!x1 && !x2 ) ans++;
}
}
F(i,1,tmp[0]) c[tmp[i]]=0;
return ans;
}
int main(){
n=read();
t=read();
m=read();
F(i,1,n) a[i]=read(),mx=max(mx,a[i]);
t=bl(n);
F(i,1,t){
ms(0,c);
int s=st(i);
int e=ed(i);
F(j,s,e) c[a[j]]++;
F(j,1,mx) cnt[j][i]=cnt[j][i-1]+c[j];
}
F(i,1,t){
ms(0,c);
int ans=0;
F(j,i,t){
int s=st(j);
int e=ed(j);
F(p,s,e) {
c[a[p]]++;
if(c[a[p]]>1 && c[a[p]]% 2==1) ans--;
else if(c[a[p]] % 2==0 && c[a[p]]>1) ans++;
}
num[i][j]=ans;
}
}
int x=0;
ms(0,c);
while (m--){
int l=read();
int r=read();
l=(l+x) % n;
r=(r+x) % n;
if(l>r) swap(l,r);
printf("%d\n",x=query(l+1,r+1) ) ;
}
return 0;
}