8
11
2015
0

2821: 作诗(Poetize)

2821: 作诗(Poetize)

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

 

分块算法

这道题空间上n会被卡内存,蒟蒻wy表示不会空间为 n 的做法,只好把开到320勉强压过。。。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int N,M,c,K,o;
int ans;
int A[100001];
int cnt[320][100001];
int Ans[320][320];
int ctmp[100001];
void PreTreatment(){
    int w=N/K;
    if (N%K) ++w;
    o=0;
    for (int i=1;i<=N;++i){
        if (i%K==1) ++o;
        for (int k=o;k<=w;++k)
            ++cnt[k][A[i]];
    }
    for (int k=1;k<=o;++k){
        int tot=0;
        memset(ctmp+1,0,sizeof(int)*c);
        for (int i=(k-1)*K+1;i<=N;++i){
            ++ctmp[A[i]];
            if ((ctmp[A[i]]%2)&&(ctmp[A[i]]!=1)) --tot;
            if (!(ctmp[A[i]]%2)) ++tot;
            if (!(i%K)) Ans[k][i/K]=tot;
            if (i==N) Ans[k][o]=tot;
        }
    }
}
int main(){
    scanf("%d%d%d",&N,&c,&M);
    K=sqrt(N);
    for (int i=1;i<=N;++i)
        scanf("%d",&A[i]);
    PreTreatment(); 
    for (;M--;){
        memset(ctmp+1,0,sizeof(int)*c);
        int l,r;
        scanf("%d%d",&l,&r);
        l=(l+ans)%N+1;
        r=(r+ans)%N+1;
        if (l>r) swap(l,r);
        int x=(l-1)/K+1;
        int y=(r-1)/K+1;
        if (l%K!=1) ++x;
        if (r%K) --y;
        if (x>y){
            ans=0;
            for (int i=l;i<=r;++i){
                ++ctmp[A[i]];
                if ((ctmp[A[i]]%2)&&(ctmp[A[i]]!=1)) --ans;
                if (!(ctmp[A[i]]%2)) ++ans;
            }
        }
        else{
            ans=Ans[x][y];
            for (int i=l;i<=(x-1)*K;++i){
                ++ctmp[A[i]];
                int tmp=cnt[y][A[i]]-cnt[x-1][A[i]]+ctmp[A[i]];
                if ((tmp%2)&&(tmp!=1)) --ans;
                if (!(tmp%2)) ++ans;
            }
            for (int i=y*K+1;i<=r;++i){
                ++ctmp[A[i]];
                int tmp=cnt[y][A[i]]-cnt[x-1][A[i]]+ctmp[A[i]];
                if ((tmp%2)&&(tmp!=1)) --ans;
                if (!(tmp%2)) ++ans;
            }
        }
        printf("%d\n",ans);
    }
}
Category: BZOJ | Tags: bzoj 分块算法 | Read Count: 377

登录 *


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