[BZOJ4869][六省联考2017]相逢是问候(线段树+扩展欧拉定理)

4869: [Shoi2017]相逢是问候

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 1313  Solved: 471
[Submit][Status][Discuss]

Description

Informatikverbindetdichundmich.

信息将你我连结。B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数。一共有m个操作,可以

分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是

输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为

这个结果可能会很大,所以你只需要输出结果mod p的值即可。

Input

第一行有三个整数n,m,p,c,所有整数含义见问题描述。

接下来一行n个整数,表示a数组的初始值。

接下来m行,每行三个整数,其中第一个整数表示了操作的类型。

如果是0的话,表示这是一个修改操作,操作的参数为l,r。

如果是1的话,表示这是一个询问操作,操作的参数为l,r。

1 ≤ n ≤ 50000, 1 ≤ m ≤ 50000, 1 ≤ p ≤ 100000000, 0 < c <p, 0 ≤ ai < p

Output

对于每个询问操作,输出一行,包括一个整数表示答案mod p的值。

Sample Input

4 4 7 2
1 2 3 4
0 1 4
1 2 4
0 1 4
1 1 3

Sample Output

0
3

HINT

鸣谢多名网友提供正确数据,已重测!

Source

黑吉辽沪冀晋六省联考&&鸣谢xlk授权本OJ使用权

[Submit][Status][Discuss]

扩展欧拉定理:$a^x \equiv a^{x\% \phi (p)+[x> \phi (p)] \phi (p)} (mod p)$,a和p可以不互质。

我们可以不断展开:$c^{c^x} \equiv c^{c^x\% \phi (p)+\phi(p) } \equiv c^{c^{x\% \phi(\phi(p))+\phi(\phi(p))}\%\phi(p)+\phi(p)}(mod p)$,以此类推。

可以证明在$O(\log n)$次内模数会变为1,也就是最后会变成$x\%1+1$所以这个直接用线段树维护就好,如果一个区间内的所有数都变成1了就不必处理。

注意最后要加一个$\phi(1)$:https://blog.csdn.net/llgyc/article/details/71076172

#include<cstdio>
#include<algorithm>
#define ls (x<<1)
#define rs (x<<1)|1
#define lson ls,L,mid
#define rson rs,mid+1,R
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std;

const int N=100010;
int n,m,op,l,r,a[N],cnt,c,dep[N<<2];
ll sum[N<<2],mod[N];

ll phi(ll x){
	ll res=x;
	for (int i=2; i*i<=x; i++)
		if (!(x%i)){
			res=res*(i-1)/i;
			while (!(x%i)) x/=i;
		}
	if (x>1) res=res*(x-1)/x;
	return res;
}

ll pow(ll a,ll b,ll p,bool &f){
	ll res=1; f=0;
	while (b){
		if (b & 1) f|=(res*a>=p),res=(res*a)%p;
		f|=(a*a>=p && b>1); a=(a*a)%p; b>>=1;
	}
	return res;
}

ll calc(ll x,ll p){
	ll res=x; bool f;
	if (res>=mod[p]) res=res%mod[p]+mod[p];
	while (p--){
		res=pow(c,res,mod[p],f);
		if (f) res+=mod[p];
	}
	return res%mod[0];
}

void build(int x,int L,int R){
	if (L==R) { dep[x]=0; sum[x]=a[L]; return; }
	int mid=(L+R)>>1;
	build(ls,L,mid); build(rs,mid+1,R);
	sum[x]=(sum[ls]+sum[rs])%mod[0];
}

void mdf(int x,int L,int R,int l,int r){
	if (dep[x]>=cnt) return;
	if (L==R){ sum[x]=calc(a[L],++dep[x]); return; }
	int mid=(L+R)>>1;
	if (r<=mid) mdf(lson,l,r);
	else if (l>mid) mdf(rson,l,r);
		else mdf(lson,l,mid),mdf(rson,mid+1,r);
	dep[x]=min(dep[ls],dep[rs]); sum[x]=(sum[ls]+sum[rs])%mod[0];
}

ll que(int x,int L,int R,int l,int r){
	if (L==l && r==R) return sum[x];
	int mid=(L+R)>>1;
	if (r<=mid) return que(lson,l,r);
	else if (l>mid) return que(rson,l,r);
		else return (que(lson,l,mid)+que(rson,mid+1,r))%mod[0];
}

int main(){
	freopen("verbinden.in","r",stdin);
	freopen("verbinden.out","w",stdout);
	scanf("%d%d%lld%d",&n,&m,&mod[0],&c);
	while (mod[cnt]!=1) cnt++,mod[cnt]=phi(mod[cnt-1]);
	mod[++cnt]=1;
	rep(i,1,n) scanf("%d",&a[i]);
	build(1,1,n);
	while (m--){
		scanf("%d%d%d",&op,&l,&r);
		if (!op) mdf(1,1,n,l,r); else printf("%lld\n",que(1,1,n,l,r));
	}
	return 0;
}

原文地址:https://www.cnblogs.com/HocRiser/p/8656701.html

时间: 2024-10-15 02:08:18

[BZOJ4869][六省联考2017]相逢是问候(线段树+扩展欧拉定理)的相关文章

bzoj千题计划271:bzoj4869: [六省联考2017]相逢是问候

http://www.lydsy.com/JudgeOnline/problem.php?id=4869 欧拉降幂+线段树,每个数最多降log次,模数就会降为1 #include<cmath> #include<cstdio> #include<iostream> using namespace std; #define N 50001 int n,m,p,c; int a[N]; int sum[N<<2]; int tag[N<<2]; in

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

传送门 题解 扩展欧拉定理. 线段树维护,已经全改到底了的节点就不管,不然暴力修改下去. //Achen #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<queue> #include<cmath> const int N=5

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

相逢是问候 2017-09-09 Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为这个结果可

[六省联考2017]相逢是问候(线段树+拓展欧拉定理)

好题啊! 调了一个中午,发现有一条语句 \(RE\) 了.在 \(windows\) 下没关系,\(linux\) 下有问题,大大的问题. while(phi[tot]!=1) phi[++tot]=calc_phi(phi[tot-1]); 算是拓展欧拉定理的题吧.线段树只是一个工具,最主要还是暴力修改.因为 \(\varphi\) 不断套下去最多会有 \(\lfloor \log n\rfloor\) 层,所以我们对于每一层暴力算一遍,加上快速幂,时间复杂度 \(O(n\log^3 n)\)

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

题意 如果对一个数操作\(k\)次,那么这个数会变成\(c^{c^{...^{a_i}}}\),其中\(c\)有\(k\)个. 根据P4139 上帝与集合的正确用法这道题,我们可以知道一个数不断变为自己的欧拉函数,大约\(log\)次就会变成1,而任何数模\(1\)都是\(0\),于是我们可以用势能线段树解决. 因为模数不变,因此我们可以预处理所有\(\varphi(\varphi(...\varphi(p)...))\),之后在线段树上记录操作次数. 这样是三个\(log\)的,因为还要快速幂

【bzoj4869】[Shoi2017]相逢是问候 线段树+扩展欧拉定理

Description Informatikverbindetdichundmich. 信息将你我连结.B君希望以维护一个长度为n的数组,这个数组的下标为从1到n的正整数.一共有m个操作,可以 分为两种:0 l r表示将第l个到第r个数(al,al+1,...,ar)中的每一个数ai替换为c^ai,即c的ai次方,其中c是 输入的一个常数,也就是执行赋值ai=c^ai1 l r求第l个到第r个数的和,也就是输出:sigma(ai),l<=i<=rai因为 这个结果可能会很大,所以你只需要输出结

P3746 [六省联考2017]组合数问题

P3746 [六省联考2017]组合数问题 \(dp_{i,j}\)表示前\(i\)个物品,取的物品模\(k\)等于\(r\),则\(dp_{i,j}=dp_{i-1,(j-1+k)%k}+dp_{i-1,j}\) \(dp_{i,0},dp_{i,1},dp_{i,2}.....dp_{i,k-1}\) \(\Longrightarrow\) \(dp_{i+1,0},dp_{i+1,1},dp_{i+1,2}.....dp_{i+1,k-1}\) 仔细想想,你能构造出矩阵的 #include

[luogu] P3745 [六省联考2017]期末考试 (贪心)

P3745 [六省联考2017]期末考试 题目描述 有 \(n\) 位同学,每位同学都参加了全部的 \(m\) 门课程的期末考试,都在焦急的等待成绩的公布. 第 \(i\) 位同学希望在第 \(t_i\)? 天或之前得知所有课程的成绩.如果在第 \(t_i\) 天,有至少一门课程的成绩没有公布,他就会等待最后公布成绩的课程公布成绩,每等待一天就会产生 \(C\) 不愉快度. 对于第 \(i\) 门课程,按照原本的计划,会在第 \(b_i\)? 天公布成绩. 有如下两种操作可以调整公布成绩的时间:

bzoj千题计划265:bzoj4873: [六省联考2017]寿司餐厅

http://www.lydsy.com/JudgeOnline/problem.php?id=4873 选a必选b,a依赖于b 最大权闭合子图模型 构图: 1.源点 向 正美味度区间 连 流量为 美味度 的边 2.负美味度区间 向 汇点 连 流量为 美味度的绝对值 的边 3.区间[i,j] 向 区间[i+1,j].区间[i,j-1] 连 流量为 inf 的边 4.区间[i,i] 向 寿司i 连 流量为 inf 的边 5.寿司i 向 汇点 连 流量为 寿司代号 的边 6.寿司i 向 它的代号 连