2017六省联考 相逢是问候

题目链接:戳我

落谷时间卡得真紧。。。。test9 和test11 根本过不去,只有在BZOJ上面A掉了。。。。。。

首先可以看得出这是一个线段树维护的数据结构题目吧qwqwq

但是对于这种阶乘修改,显然是不具备可加性的,所以我们只能暴力修改。。。。但是暴力修改时间复杂度是会炸天的!

但是我们再看一下——

\(c^{a[i]^{a[i]^{...}}} \pmod p\)
我们想到了什么!!!——拓展欧拉定理啊qwqwq

\[a^b\equiv\begin{cases}a^{b\%\phi(p)}&{gcd(a,p)=1}\\a^b&{gcd(a,p)1,b\le\phi(p)}\\a^{b\%\phi(p)+\phi(p)}&gcd(a,p)\neq1,b\ge\phi(p)\end{cases}\pmod p \]

(其实大家可以先去看看【上帝与集合的正确用法】这个题,想必是有一些启发的)

根据拓展欧拉定理,显然我们递归几次这个模数就会变成1,当模数变成1的时候,显然就不需要再次计算了。

举个例子:

\[c^{a[i]^{a[i]}}=c^{a[i]^{a[i]\%\phi(\phi(p))+\phi(\phi(p))}+\phi(p)} \]

所以我们可以预先处理出来p的phi值都是多少,结束条件为phi值==1。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define MAXN 100010
using namespace std;
int n,m,c,p,cnt;
int a[MAXN],phi[MAXN];
struct Node{int l,r,tot,sum;}t[MAXN<<2];

inline int Phi(int x)
{
	long long cur_ans=x;
	int now=x;
	for(int i=2;i*i<=now;i++)
	{
		if(now%i==0) cur_ans=cur_ans/i*(i-1);
		while(now%i==0) now/=i;
	}
	if(now>1) cur_ans=cur_ans/now*(now-1);
	return cur_ans;
}

inline void init()
{
	int cur=p;
	while(cur>1)
	{
		cur=Phi(cur);
		phi[++cnt]=cur;
	}
	//for(int i=1;i<=cnt;i++) printf("phi[%d]=%d\n",i,phi[i]);
}

inline long long fpow(long long x,long long y,long long mod)
{
	long long cur_ans=1;
	int flag1=0,flag2=0;
	while(y)
	{
		if(y&1) cur_ans=cur_ans*x,flag1|=flag2;
		if(cur_ans>=mod) flag1=1,cur_ans%=mod;
		x=x*x;
		if(x>=mod) flag2=1,x%=mod;
		y>>=1;
	}
	if(flag1) cur_ans+=mod;
	return cur_ans;
}

inline long long solve(int l,int r,long long x,long long mod)
{
	if(l==r) return x;
	return fpow(c,solve(l+1,r,x,phi[l+1]),mod);
}

inline int ls(int x){return x<<1;}

inline int rs(int x){return x<<1|1;}

inline void push_up(int x)
{	
	t[x].sum=(t[ls(x)].sum+t[rs(x)].sum)%p;
	t[x].tot=min(t[ls(x)].tot,t[rs(x)].tot);
}

inline void build(int x,int l,int r)
{
	t[x].l=l,t[x].r=r;
	if(l==r){t[x].sum=a[l];return;}
	int mid=(l+r)>>1;
	build(ls(x),l,mid);
	build(rs(x),mid+1,r);
	push_up(x);
}

inline void update(int x,int ll,int rr)
{
	if(t[x].tot>cnt) return;
	int l=t[x].l,r=t[x].r;
	if(l==r)
	{
		t[x].sum=solve(0,++t[x].tot,a[l],p)%p;
		return;
	}
	int mid=(l+r)>>1;
	if(ll<=mid) update(ls(x),ll,rr);
	if(mid<rr) update(rs(x),ll,rr);
	push_up(x);
}

inline long long query(int x,int ll,int rr)
{
	int l=t[x].l,r=t[x].r;
	if(ll<=l&&r<=rr) return t[x].sum%p;
	int mid=(l+r)>>1;
	long long cur_ans=0;
	if(ll<=mid) cur_ans=(cur_ans+query(ls(x),ll,rr))%p;
	if(mid<rr) cur_ans=(cur_ans+query(rs(x),ll,rr))%p;
	return cur_ans;
}

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("ce.in","r",stdin);
	#endif
	scanf("%d%d%d%d",&n,&m,&p,&c);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	build(1,1,n);
	init();
	//for(int i=1;i<=cnt;i++) printf("%d\n",phi[i]);
	for(int i=1;i<=m;i++)
	{
		int op,l,r;
		scanf("%d%d%d",&op,&l,&r);
		if(op==0) update(1,l,r);
		else printf("%lld\n",query(1,l,r));
	}
	return 0;	
}
posted @ 2019-03-10 16:46  风浔凌  阅读(153)  评论(0编辑  收藏  举报