9
10
2015
0

2821: 作诗(Poetize)

2821: 作诗(Poetize)

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

    感觉是一道很好的题。

    感谢PoPoQQQ的题解和hzw的代码,研究一节音乐课一后终于懂了。。然而因为昨天太忙了。。。现在才有时间打出来。。

    我们先预处理任意两个块之间的答案,直接暴力扫一遍就可以得到

    然后考虑询问,因为我们已经知道了中间块的答案,所以只要考虑两头的块的数字对答案的影响。所以我们暴力考虑每一个在两头中多出来的数字,求在询问区间中出现的总次数和在中间完整块出现的次数,然后判断这个数对答案是否有影响。至于如何求一个数在区间中出现的次数。。可以二分上边界和下边界。。然后减一下。。

    每块大小:\(\sqrt {n\over log(n)}\)  复杂度:\(n\sqrt{n}*log(n)\)

    附带从hzw里偷来的块大小的分析:

    设分块大小为:\(x\),分块数为:\(\frac nx\),预处理:\(\frac nx *n\)

    \(n\)与\(m\)同级,视为\(n\)个询问,每次询问二分\(x\)次\(n*x*log(n)\)(除非相同的数字很多,否则\(log(n)\)会很小)。

    \(n*(x*log(n)+\frac nx)\)

    则分块大小为:\(\sqrt {n\over log(n)}\)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6;
const int M = 2e3;
struct data{int v,id;} b[N];
int n,m,Q,blk,lastans,pos[N],L[M],R[M],a[N],tmp[N],vis[N],f[M][M],fis[N],last[N],c;
int read(){
	int x = 0,f = 1,c = getchar();
	while (c<'0' || c>'9'){if (c=='-') f = -1;c = getchar();}
	while (c>='0' && c<='9') x = x*10+c-'0',c = getchar();
	return  x*f;
}
bool cmp(data a,data b){if (a.v==b.v) return a.id<b.id;return a.v<b.v;}
void Prepare(){
	for (int i=1;i<=m;i++){
		int tot = 0;
		for (int j=L[i];j<=n;j++) tmp[a[j]] = 0;
		for (int j=L[i];j<=n;j++){
			if (!(tmp[a[j]]&1) && tmp[a[j]]) tot--;
			tmp[a[j]]++;
			if (!(tmp[a[j]]&1)) tot++;
			f[i][pos[j]] = tot;
		}
	}
	for (int i=1;i<=n;i++) b[i].v = a[i],b[i].id = i;
	sort(b+1,b+1+n,cmp);
	for (int i=1;i<=n;i++){
		if (!fis[b[i].v]) fis[b[i].v] = i;
		last[b[i].v] = i;
	}
}
int findup(int x,int val){
	int l = fis[val],r = last[val],ans = 0;
	while (l<=r){
		int mid = (l+r)>>1;
		if (b[mid].id<=x) ans = mid-fis[val],l = mid+1;
		else r = mid-1;
	}
	return ans;
}
int finddown(int x,int val){
	int l = fis[val],r = last[val],ans = last[val]+1;
	while (l<=r){
		int mid = (l+r)>>1;
		if (b[mid].id>=x) ans = mid-fis[val],r = mid-1;
		else l = mid+1;
	}
	return ans;
}
int find(int l,int r,int val){return max(findup(r,val)-finddown(l,val)+1,0);}
int Query(int x,int y){
	int ans = 0;
	if (pos[x]==pos[y] || pos[x]+1==pos[y]){
		for (int i=x;i<=y;i++){
			int A = a[i];if (vis[A]) continue;
			int t = find(x,y,A);
			if (!(t&1)) ans++;
			vis[A] = 1;
		}
		for (int i=x;i<=y;i++) vis[a[i]] = 0;
		return ans;
	}
	else {
		int l = L[pos[x]+1],r = R[pos[y]-1];
		ans = f[pos[x]+1][pos[y]-1];
		for (int i=x;i<l;i++){
			int A = a[i];if (vis[A]) continue;
			int t2 = find(l,r,A),t1 = find(x,y,A);
			if (!(t1&1)) {if (t2&1 || !t2) ans++;}
			else if (!(t2&1) && t2) ans--;
			vis[A] = 1;
		}
		for (int i=r+1;i<=y;i++){
			int A = a[i];if (vis[A]) continue;
			int t2 = find(l,r,A),t1 = find(x,y,A);
			if (!(t1&1)) {if (t2&1 || !t2) ans++;}
			else if (!(t2&1) && t2) ans--;
			vis[A] = 1;
		}
		for (int i=x;i<l;i++) vis[a[i]] = 0;
		for (int i=r+1;i<=y;i++) vis[a[i]] = 0;
		return ans;
	}
}
int main(){
	freopen("2821.in","r",stdin);
	freopen("2821.out","w",stdout);
	n = read();c = read();Q = read();
	for (int i=1;i<=n;i++) a[i] = read();
	blk = sqrt((double)n/log((double)n)*log(2));
	if (n%blk) m = n/blk+1;
	else m = n/blk;
	for (int i=1;i<=n;i++) pos[i] = (i-1)/blk+1;
	for (int i=1;i<=m;i++) L[i] = (i-1)*blk+1,R[i] = min(i*blk,n);
	Prepare();
	for (int i=1;i<=Q;i++){
		int l = read(),r = read();
		int x = (l+lastans)%n+1,y = (r+lastans)%n+1;
		if (x>y) swap(x,y);
		lastans = Query(x,y);
		printf("%d\n",lastans);
	}
}
Category: BZOJ题解 | Tags: | Read Count: 685

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com