bzoj 2821

2821: 作诗(Poetize)

Time Limit: 50 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

2
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;  
}

  

转载于:https://www.cnblogs.com/ZJXXCN/p/9702862.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值