洛谷 P3747 [六省联考 2017] 相逢是问候

题目链接

欧拉降幂最多只会迭代到第 \(k = \text O (\log p)\) 次模数就会变成 \(1\)(证明见这里)。故一个数被操作超过 \(k\) 次就会变为一个定值。

于是用线段树维护出操作还没有满 \(k\) 次的位置,每次暴力修改并计算,均摊下来只有 \(nk\) 次。光速幂可以预处理。

时间复杂度 \(\text O (k \sqrt p + nk \log n + nk ^ 2)\)

#include<cstdio>
#include<cmath>
#define N 50005
#define M 55
using namespace std;

int n,m,p,c,k,a[N],mo[M];
int pw[M][N],Pw[M][N];
int mod(long long x,int p) {
	if(x<p) return x;
	return x%p+p;
}
int phi(int x) {
	int res=x;
	for(int i=2;i<=x/i;i++) if(x%i==0) {
		res=res/i*(i-1);
		while(x%i==0) x/=i;
	}
	if(x>1) res=res/x*(x-1);
	return res;
}
int qqpow(int x,int y,int p) {
	return mod(1ll*pw[p][y&(1<<14)-1]*Pw[p][y>>14],mo[p]);
}
int calc(int x,int p,int d) {
	if(p>d) return mod(x,mo[p]);
	return qqpow(x,calc(x,p+1,d),p);
}
struct segment_tree {
	struct st {
		int l,r,c,cnt,sum; bool tag;
		#define l(p) tr[p].l
		#define r(p) tr[p].r
		#define c(p) tr[p].c
		#define cnt(p) tr[p].cnt
		#define sum(p) tr[p].sum
		#define tag(p) tr[p].tag
	} tr[N*4];
	void update(int p) {
		sum(p)=(sum(p*2)+sum(p*2+1))%mo[1];
		tag(p)=tag(p*2)|tag(p*2+1);
	}
	void build(int p,int l,int r) {
		l(p)=l,r(p)=r,tag(p)=1;
		if(l==r) {c(p)=sum(p)=a[l]; return;}
		int mid=l+r>>1;
		build(p*2,l,mid),build(p*2+1,mid+1,r);
		update(p);
	}
	void modify(int p,int l,int r) {
		if(!tag(p)) return;
		if(l(p)==r(p)) {
			cnt(p)++,sum(p)=calc(c(p),1,cnt(p))%mo[1],tag(p)=cnt(p)<k;
			return;
		}
		if(l<=r(p*2)) modify(p*2,l,r);
		if(r>=l(p*2+1)) modify(p*2+1,l,r);
		update(p);
	}
	int ask(int p,int l,int r) {
		if(l<=l(p)&&r>=r(p)) return sum(p);
		if(r<=r(p*2)) return ask(p*2,l,r);
		if(l>=l(p*2+1)) return ask(p*2+1,l,r);
		return (ask(p*2,l,r)+ask(p*2+1,l,r))%mo[1];
	}
} t1;
int main() {
	scanf("%d%d%d%d",&n,&m,&p,&c);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	while(p>1) mo[++k]=p,p=phi(p);
	mo[++k]=p;
	for(int i=1;i<=k;i++) {
		int w=1;
		for(int j=0;j<1<<14;j++) pw[i][j]=w,w=mod(1ll*w*c,mo[i]);
		int cc=w; w=1;
		for(int j=0;j<1<<14;j++) Pw[i][j]=w,w=mod(1ll*w*cc,mo[i]);
	}
	mo[k+1]=1,t1.build(1,1,n);
	for(int i=1,op,x,y;i<=m;i++) {
		scanf("%d%d%d",&op,&x,&y);
		if(!op) t1.modify(1,x,y);
		else printf("%d\n",t1.ask(1,x,y));
	}
	return 0;
}
posted @ 2026-01-19 19:29  yemuzhe  阅读(0)  评论(0)    收藏  举报