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

    【BZOJ2821】作诗(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

    题解:分块大法太强了~

    我们先分块,对于每一个询问[l,r]我们都可以将它拆成中间一堆大块和两边的小块,设f[i][j]表示从第i个块到第j个块的答案,我们先枚举每个块,暴力扫所有i块后面的点,这样就能边扫边预处理出f[i][j],到时候我们就直接调用就好了,现在我们处理两边的小块

    我们将两边小块里的元素暴力扫一遍,然后排个序,这样我们就能得到每个汉字出现的次数了,这时我们就需要提前预处理出一个g[i][j],表示在1~i的块里j出现的个数,然后我们就能得出每个汉字的总个数了

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    int n,m,c,siz,ans,num;
    int f[320][320],g[320][100010],v[100010],s[100010],p[640];
    int main()
    {
    	scanf("%d%d%d",&n,&c,&m);
    	int i,j,a,b;
    	siz=int(sqrt(1.0*n));
    	for(i=0;i<n;i++)	scanf("%d",&v[i]),g[i/siz][v[i]]++;
    	for(i=0;i<=n/siz;i++)
    	{
    		if(i)	for(j=1;j<=c;j++)	g[i][j]+=g[i-1][j];
    		memset(s,0,sizeof(s));
    		for(j=i*siz;j<n;j++)
    		{
    			s[v[j]]++;
    			if(s[v[j]]==2)	f[i][j/siz]++;
    			if(s[v[j]]==3)	f[i][j/siz]--,s[v[j]]=1;
    			if(j&&j%siz==0)	f[i][j/siz]+=f[i][j/siz-1];
    		}
    	}
    	for(i=1;i<=m;i++)
    	{
    		scanf("%d%d",&a,&b);
    		a=(a+ans)%n,b=(b+ans)%n;
    		num=0;
    		if(a>b)	swap(a,b);
    		if(a/siz==b/siz)
    		{
    			ans=0;
    			for(j=a;j<=b;j++)	p[num++]=v[j];
    			sort(p,p+num);
    			int pre=0;
    			for(j=0;j<num;j++)
    			{
    				if(j&&p[j]!=p[j-1])
    				{
    					ans+=(pre%2==0)?1:0;
    					pre=0;
    				}
    				pre++;
    			}
    			ans+=(pre%2==0)?1:0;
    		}
    		else
    		{
    			ans=f[a/siz+1][b/siz-1];
    			for(j=a;j<(a/siz+1)*siz;j++)	p[num++]=v[j];
    			for(j=b/siz*siz;j<=b;j++)	p[num++]=v[j];
    			sort(p,p+num);
    			int pre=0;
    			for(j=0;j<num;j++)
    			{
    				if(j&&p[j]!=p[j-1])
    				{
    					if(g[b/siz-1][p[j-1]]>g[a/siz][p[j-1]]&&((g[b/siz-1][p[j-1]]-g[a/siz][p[j-1]])%2==0))	ans--;
    					if((pre+g[b/siz-1][p[j-1]]-g[a/siz][p[j-1]])%2==0)	ans++;
    					pre=0;
    				}
    				pre++;
    			}
    			if(g[b/siz-1][p[num-1]]>g[a/siz][p[num-1]]&&((g[b/siz-1][p[num-1]]-g[a/siz][p[num-1]])%2==0))	ans--;
    			if((pre+g[b/siz-1][p[num-1]]-g[a/siz][p[num-1]])%2==0)	ans++;
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
  • 相关阅读:
    KETTLE封装
    基于MODBUS-RTU协议的串口编程
    阿里DRUID 配置说明及分析
    CopyOnWriteArrayList集合排序异常问题
    CopyOnWriteArrayList集合线程安全解释
    JAR包数字签名与验证
    MySQL中select * for update锁表的范围
    Kettle文本文件输出和输入控件使用中,换行符导致的问题处理
    UAP如何根据DeviceFamily显示不同的页面
    Windows 10 响应式设计和设备友好的开发
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6561615.html
Copyright © 2011-2022 走看看