zoukankan      html  css  js  c++  java
  • BZOJ2821 作诗(Poetize) 【分块】

    题目

    神犇SJY虐完HEOI之后给傻×LYD出了一题:SHY是T国的公主,平时的一大爱好是作诗。由于时间紧迫,SHY作完诗
    之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一
    些汉字构成诗。因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次。而且SHY认
    为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!)。于是SHY请LYD安排选
    法。LYD这种傻×当然不会了,于是向你请教……问题简述:N个数,M组询问,每次问[l,r]中有多少个数出现正偶
    数次。

    输入格式

    输入第一行三个整数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]。

    输出格式

    输出共m行,每行一个整数,第i个数表示SHY第i次能选出的汉字的最多种类数。

    输入样例

    5 3 5

    1 2 2 3 1

    0 4

    1 2

    2 2

    2 3

    3 5

    输出样例

    2

    0

    0

    0

    1

    提示

    对于100%的数据,1<=n,c,m<=10^5

    题解

    考虑分块处理
    如果块的大小设为(sqrt{n})
    那么我们可以用(O(nsqrt(n)))的时间预处理出每块开头到序列结尾所有数出现的次数数组(sum[b][x])
    同时预处理出(ans[i][j])表示块(i)到块(j)的答案

    对于每个询问([l,r]),我们可以直接统计得中间完整的块的答案
    对于(l,r)两边,我们扫一遍,用一个统计数组统计每个数出现的次数,配合(sum[b][x])更新答案
    最后再扫一遍清零统计数组
    询问复杂度(O(msqrt{n}))

    总的复杂度(O(nsqrt{n} + msqrt{n}))

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 100010,maxb = 330,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int n,m,A[maxn],B,Bm,b[maxn],tot[maxn],head[maxn],tail[maxn];
    short sum[maxb][maxn],ans[maxb][maxb];
    void readin(){
    	n = read(); read(); m = read(); B = (int)ceil(sqrt(n)); Bm = n / B + 1;
    	for (int i = 1; i <= n; i++){
    		A[i] = read();
    		b[i] = i / B + 1;
    		if (b[i] != b[i - 1]) head[b[i]] = i,tail[b[i - 1]] = i - 1;
    		if (i + 1 > n) tail[b[i]] = i;
    	}
    }
    void init(){
    	int cnt;
    	for (int i = 1; i <= Bm; i++){
    		cnt = 0;
    		for (int j = head[i]; j <= n; j++){
    			if (sum[i][A[j]] & 1) cnt++;
    			else if (sum[i][A[j]]) cnt--;
    			sum[i][A[j]]++;
    			if (tail[b[j]] == j) ans[i][b[j]] = cnt;
    		}
    	}
    }
    void solve(){
    	int cnt = 0,l,r,L,R,tmp;
    	while (m--){
    		l = (read() + cnt) % n + 1; r = (read() + cnt) % n + 1;
    		if (l > r) swap(l,r);
    		if (b[r] - b[l] > 1){
    			cnt = ans[b[l] + 1][b[r] - 1];
    			L = b[l] + 1;
    			R = b[r];
    		}
    		else {
    			cnt = 0;
    			L = R = b[l] + 1;
    		}
    		if (b[l] == b[r]){
    			for (int i = l; i <= r; i++){
    				if (tot[A[i]] & 1) cnt++;
    				else if (tot[A[i]]) cnt--;
    				tot[A[i]]++;
    			}
    			for (int i = l; i <= r; i++) tot[A[i]]--;
    		}
    		else {
    			for (int i = l; i <= tail[b[l]]; i++){
    				tmp = tot[A[i]] + sum[L][A[i]] - sum[R][A[i]];
    				if (tmp & 1) cnt++;
    				else if (tmp) cnt--;
    				tot[A[i]]++;
    			}
    			for (int i = head[b[r]]; i <= r; i++){
    				tmp = tot[A[i]] + sum[L][A[i]] - sum[R][A[i]];
    				if (tmp & 1) cnt++;
    				else if (tmp) cnt--;
    				tot[A[i]]++;
    			}
    			for (int i = l; i <= tail[b[l]]; i++) tot[A[i]]--;
    			for (int i = head[b[r]]; i <= r; i++) tot[A[i]]--;
    		}
    		printf("%d
    ",cnt);
    	}
    }
    int main(){
    	readin();
    	init();
    	solve();
    	return 0;
    }
    
    
  • 相关阅读:
    thinkphp3.2生成二维码
    php实现图片下载
    yii2.0 Activeform表单部分组件使用方法
    Yii2美化confirm
    Yii2学习笔记之场景
    tp5页面输出时,搜索后跳转下一页的处理
    php页面输出时,js设置input框的选中值
    mac中使用rz,sz上传文件
    golang的命令行程序开发
    Sring MVC基于Java Config方式配置Mybatis, 无XML
  • 原文地址:https://www.cnblogs.com/Mychael/p/8876814.html
Copyright © 2011-2022 走看看