Always keep a b|

luckydrawbox

园龄:4个月粉丝:1关注:2

P4681 [THUSC2015] 平方运算

Link\text{Link}

题意

给定长度为 nn 的序列和一个数 pp,有 mm 个操作:

  • 1 l r:将区间 [l,r][l,r] 内的数分别平方对 pp 取模。
  • 2 l r:求区间 [l,r][l,r] 内的数的和。

分析

看到修改如此诡异,考虑分块。

注意到值域很小,且 pp 有时不是质数,这启发我们要从打表开始着手。

经过打表可得,对于题目中的所有 pp,每个数进行平方运算的循环节长度 tim60tim\le60,一个数要进入循环需要的次数 lim11lim\le11,且对于同一个 pp,任意两个不同的数的循环节 lim1,lim2(lim1lim2)lim1,lim2(lim1\le lim2) 满足 lim1lim2lim1\mid lim2。于是我们只要知道对于一个 pp 的最大循环节长度,将其作为每个数的循环节长度即可。

为了优化常数,可以预处理出每个数乘方若干次后的值。然后就是众所周知的操作:

  • 对于散块,查询和修改都直接暴力即可,同时维护 sumk,0tim1sum_{k,0\sim tim-1} 表示块 kk 修改 0tim10\sim tim-1 次后的和。
  • 对于整块,查询直接 O(1)O(1) 回答,修改则要分两种情况:若该块修改次数不超过 limlim,说明可能有的数还没进入循环,当成散块暴力改;若超过 limlim 次,直接 O(1)O(1) 改变标记即可。

等等,这样复杂度好像要带上 60\sqrt {60} 的常数?那不炸飞了,考虑优化。

我们发现散块的复杂度偏高了,于是可以改为在暴力的同时,只维护 sumk,0sum_{k,0},当后面要用到 sumk,xsum_{k,x} 时,重新求一下即可。感觉比较玄学,但是好像能均摊的样子,于是就过了。(

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
	long long x=0,f=1;char ch=getchar();
	while(!isdigit(ch))
	{if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
void write(long long x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
const int N=1e5+10,sN=330,S=1e4+10;
int n,m,p,len,nxt[S][61],a[N],tim[sN],lim[sN];
int id,pri[21]={233,2332,5,8192,23,45,37,4185,5850,2975
,2542,2015,2003,2010,4593,4562,1034,5831,9905,9977};
bool vis[N],fl[N];
int cnt[sN],tag[sN];
bool dos[sN][61];
int sum[sN][61],now[sN];
void init(){
	tim[0]=28;lim[0]=3;
	tim[1]=12;lim[1]=2;
	tim[2]=1;lim[2]=2;
	tim[3]=1;lim[3]=11;
	tim[4]=10;lim[4]=1;
	tim[5]=2;lim[5]=2;
	tim[6]=6;lim[6]=2;
	tim[7]=12;lim[7]=2;
	tim[8]=4;lim[8]=2;
	tim[9]=4;lim[9]=4;
	tim[10]=4;lim[10]=3;
	tim[11]=4;lim[11]=2;
	tim[12]=60;lim[12]=1;
	tim[13]=10;lim[13]=2;
	tim[14]=24;lim[14]=1;
	tim[15]=36;lim[15]=3;
	tim[16]=44;lim[16]=1;
	tim[17]=42;lim[17]=4;
	tim[18]=46;lim[18]=2;
	tim[19]=60;lim[19]=1;
}
void solve(int u){//打表 
	int P=pri[u];
	int mx=0,m2=0;
	memset(fl,0,sizeof(fl));
	for(int i=1;i<P;i++){
		memset(vis,0,sizeof(vis));
		int j=i%P;
		int len=0;
		while(!vis[j]){
			len++;
			vis[j]=1;
			j=j*j%P;
		}
		if(j==i)fl[len]=1,mx=max(mx,len);
		m2=max(m2,len);
	}
	printf("tim[%d]=%d;lim[%d]=%d;\n",u,mx,u,m2-mx);
}
void pushdown(int k){
	if(tag[k]){
		for(int i=max(k*len,1);i<=min(n,k*len+len-1);i++){
			a[i]=nxt[a[i]][tag[k]];
		}
		tag[k]=0;
	}
}
void pushup(int k){
	memset(dos[k],0,sizeof(dos[k]));
	memset(sum[k],0,sizeof(sum[k]));
	dos[k][0]=1;
	for(int i=max(k*len,1);i<=min(n,k*len+len-1);i++){
		sum[k][0]+=a[i];
	}
}
void change(int l,int r){
	int kl=l/len,kr=r/len;
	if(kl==kr){
		pushdown(kl);
		for(int i=l;i<=r;i++){
			a[i]=nxt[a[i]][1];
		}
		pushup(kl);
		return;
	}
	change(l,(kl+1)*len-1);
	change(kr*len,r);
	for(int i=kl+1;i<kr;i++){
		if(cnt[i]<=lim[id]){
			cnt[i]++;
			change(i*len,(i+1)*len-1);
			continue;
		}
		tag[i]=(tag[i]+1)%tim[id];
	}
}
int ask(int l,int r){
	int kl=l/len,kr=r/len;
	int ans=0;
	if(kl==kr){
		pushdown(kl);
		for(int i=l;i<=r;i++){
			ans+=a[i];
		}
		pushup(kl);
		return ans;
	}
	ans=ask(l,(kl+1)*len-1)+ask(kr*len,r);
	for(int i=kl+1;i<kr;i++){
		if(!dos[i][tag[i]]){
			dos[i][tag[i]]=1;
			for(int j=max(i*len,1);j<=min(n,i*len+len-1);j++){
				sum[i][tag[i]]+=nxt[a[j]][tag[i]];
			}
		}
		ans+=sum[i][tag[i]]; 
	}
	return ans;
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	n=read();m=read();p=read();
	len=sqrt(n);
	init();
	for(int i=0;i<20;i++){
		if(p==pri[i]){
			id=i;
		}
	}
	for(int i=1;i<p;i++){
		nxt[i][0]=i;
	}
	for(int i=1;i<=60;i++){
		for(int j=1;j<p;j++){
			nxt[j][i]=nxt[j][i-1];
			nxt[j][i]=(nxt[j][i]*nxt[j][i])%p;
		}
	}
	for(int i=1;i<=n;i++){
		a[i]=read();
	}
	for(int k=0;k<=n/len;k++){
		pushup(k);
	}
	for(int i=1;i<=m;i++){
		int op=read(),l=read(),r=read();
		if(op==1){
			change(l,r);
		}
		else {
			write(ask(l,r));
			puts("");
		}
	}
	return 0;
}

本文作者:luckydrawbox

本文链接:https://www.cnblogs.com/luckydrawbox/p/18526441

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   luckydrawbox  阅读(2)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起