P4135 作诗

参考

题意:给定数列,mm次询问 [ l i , r i ] [l_i,r_i] [li,ri]中,出现正偶数次的数的个数。

idea:之前我们是做过问区间众数的题的,这题跟那题比较类似,但不完全相同。我们需要预处理出 c n t [ i ] [ j ] cnt[i][j] cnt[i][j] 为前 i i i块中 j j j出现的次数 a n s [ i ] [ j ] ans[i][j] ans[i][j] i i i块到第 j j j块中出现偶数次的数的个数

ACcode:

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#include<cmath>
#define N 100010
#define SQ 1010
using namespace std;

int n,m,c,cnt[SQ][N],ans[SQ][SQ],val[N],bl[N],st[SQ],ed[SQ],maxx=-1,t[N],sq;

void init()
{
	for(int i=1;i<=bl[n];i++)
	{
		st[i] = (i-1)*sq + 1;
		ed[i] = i*sq ; 
	}
	ed[ bl[n] ] = n;
	for(int i=1;i<=bl[n];i++)
	{
		for(int j=0;j<=c;j++)
		{
			cnt[i][j] += cnt[i-1][j];
		}
	}
	for(int i=1;i<=bl[n];i++)
	{
		for(int j=i;j<=bl[n];j++)
		{
			ans[i][j] = ans[i][j-1];
			for(int k=st[j];k<=ed[j];k++)
			{
				t[ val[k] ]++;
				if( t[ val[k] ]%2==0 ) ans[i][j]++;
				else if( t[ val[k] ]>=3 ) ans[i][j]--;
			}
		}
		memset(t,0,sizeof(t));
	}
}

int query(int l,int r)
{
	int sum = 0;
	if( bl[l]+1>=bl[r] )//特别注意,这题当[l,r]都相邻两个块或者同一个块是要直接加不然会出问题
	{
		for(int i=l;i<=r;i++)
		{
			t[ val[i] ]++;
			if( t[ val[i] ]%2==0 ) sum++;//说明在t[]在+1之前是奇数,所以这是一种新方案
			else if( t[ val[i] ]>=3 ) sum--; //说明t[]在+1之前是偶数,并且之前的t[]>=2故sum需-1
		}
		for(int i=l;i<=r;i++) t[ val[i] ]--;
		return sum;
	}
	sum = ans[ bl[l]+1 ][ bl[r]-1 ];
	for(int i=l;i<=min( r,ed[ bl[l] ] );i++)
	{
		t[ val[i] ]++;
		int v = cnt[ bl[r]-1 ][ val[i] ] - cnt[ bl[l] ][ val[i] ];
		if( (t[ val[i] ]+v)%2==0 ) sum++;
		else if( (t[ val[i] ]+v)>=3 ) sum--;
	}
	if( bl[l] != bl[r] )
	{
		for(int i=st[ bl[r] ];i<=r;i++)
		{
			t[ val[i] ]++;
			int v = cnt[ bl[r]-1 ][ val[i] ] - cnt[ bl[l] ][ val[i] ];
			if( (t[ val[i] ]+v)%2==0 ) sum++;
			else if( t[ val[i] ]+v >=3 ) sum--;
		}
		for(int i=st[ bl[r] ];i<=r;i++) t[ val[i] ]--;
	}
	for(int i=l;i<=min( r,ed[bl[l]] );i++) t[ val[i] ]--;
	return sum;
}

void solve()
{
	scanf("%d %d %d",&n,&c,&m);
	sq = sqrt(n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&val[i]);
		bl[i] = (i-1)/sq + 1;
		cnt[ bl[i] ][ val[i] ]++;
	}
	
	init();
	int as = 0;
	while( m-- )
	{
		int l,r;
		scanf("%d %d",&l,&r);
		l = (l+as) % n + 1;
		r = (r+as) % n + 1;
		if( l>r ) swap( l,r );
		as = query( l,r );
		printf("%d\n",as);
	}
}

signed main()
{
		//freopen("in.txt","r",stdin);
	
	solve();
	return 0;
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值