Loading

题解 【CF1109E Sasha and a Very Easy Test】

\(\Large\texttt{CF1109E}\)

前置知识:欧拉定理(扩展费马小定理),基本线段树操作

题意

十分简洁,不多赘述。

注意 \(mod\) 可以不为质数,每个单点除操作保证能整除。

思路

\(mod\) 是质数就好做了(不然怎么会是黑题),但 \(mod\) 不是质数代表在单点除时不能直接用费马小定理边乘边模。

可以考虑使用扩展费马定理:

\[a^{\varphi(p)}=1\mod p ~~(\gcd(a,p)=1) \]

发现小于 \(1e9\) 的每个数质因数个数不会超过 \(9\) 个,可以想到将所有要进行操作的数分成两部分,一部分质因子全是 \(mod\) 的质因子,开一个大小为 \(10\) 的数组暴力操作,若除就在这个数组里面减去要减的质因子,剩下部分的肯定与 \(mod\) 互质,除一个数就乘 \(x^{\varphi(mod)-1}\) 并取模就好了。

注意细节,可以参考代码。

另附上 \(\varphi(n)\) 的求法:

\[\varphi(n)=n\times\prod^{x}_{i=1}\frac{p_i}{p_i-1} \]

不要像我 \(\varphi\) 求错了调1h

时间复杂度 \(\texttt{O(10NlogN)}\) (远远达不到这个上限)。

代码

#include <bits/stdc++.h>
using namespace std;

 #define ls n << 1
 #define rs n << 1 | 1
 #define int long long
 const int N = 1e5;
inline int read()
{
    int s = 0;
    register bool neg = 0;
    register char c = getchar();
    for (; c < '0' || c > '9'; c = getchar())
        neg |= (c == '-');
    for (; c >= '0' && c <= '9'; s = s * 10 + (c ^ 48), c = getchar())
        ;
    s = (neg ? -s : s);
    return s;
}

int a,mod,b,p[10],top,q[N+10],t[N+10][10],add[10],pp;
struct segment {
	int l,r,val,lazy1[10],lazy2,lazy3;
} s[N*4+10];

inline int get_phi(int n) {
	int ans = n;
	for (int i = 2; i*i <= n; i++) {
		if (!(n%i)) {
			ans = 1ll * ans * (i - 1) / i;
			while (!(n%i))n /= i;
		}
	}
	if (n > 1)ans = 1ll * ans * (n - 1) / n;
	return ans;
}

inline void get(int n) {
	int qq=sqrt(n);
	for(int i=2;i<=qq;i++) {
		if(n%i==0) {
			p[++top]=i;
			while(n%i==0) n/=i;
		}
	}
	if(n!=1) p[++top]=n;
}

inline int qpow(int n,int m) {
	int res=1;
	for(;m;m>>=1) {
		if(m&1) res=res*n%mod;
		n=n*n%mod;
	}
	return res;
}

inline int calc(int n) {
	int res=1;
	for(int i=1;i<=top;i++) res=(res*qpow(p[i],t[n][i]))%mod;
	return res;
}

inline void up(int n) {
	s[n].val=(s[ls].val+s[rs].val)%mod;
}

inline void down(int n) {
	s[ls].val=s[ls].val*s[n].lazy2%mod;
	s[rs].val=s[rs].val*s[n].lazy2%mod;
	s[ls].lazy2=s[ls].lazy2*s[n].lazy2%mod;
	s[rs].lazy2=s[rs].lazy2*s[n].lazy2%mod;
	s[ls].lazy3=s[ls].lazy3*s[n].lazy3%mod;
	s[rs].lazy3=s[rs].lazy3*s[n].lazy3%mod;
	s[n].lazy2=s[n].lazy3=1;
	for(int i=1;i<=top;i++) {
		s[ls].lazy1[i]+=s[n].lazy1[i];
		s[rs].lazy1[i]+=s[n].lazy1[i];
		s[n].lazy1[i]=0;
	}
	return;
}

inline void build(int n,int l,int r) {
	s[n].l=l;
	s[n].r=r;
	s[n].lazy2=s[n].lazy3=1;
	memset(s[n].lazy1,0,sizeof(s[n].lazy1));
	if(l==r) {
		s[n].val=q[l]*calc(l)%mod;
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	up(n);
}

inline void div(int n,int m,int k) {
	if(s[n].l==s[n].r) {
		q[m]=q[m]*s[n].lazy3%mod;
		s[n].lazy3=1;
		for(int i=1;i<=top;i++) {
			t[m][i]+=s[n].lazy1[i];
			s[n].lazy1[i]=0;
			while(k%p[i]==0) t[m][i]--,k/=p[i];
		}
		q[m]=q[m]*qpow(k,pp-1)%mod;
		s[n].val=q[m]*calc(m)%mod;
		return;
	}
	down(n);
	int mid=(s[n].l+s[n].r)>>1;
	if(m<=mid) div(ls,m,k);
	else div(rs,m,k);
	up(n);
}

inline void times(int n,int l,int r,int k,int _k) {
	if(s[n].l>=l&&s[n].r<=r) {
		s[n].val=s[n].val*k%mod;
		s[n].lazy2=s[n].lazy2*k%mod;
		s[n].lazy3=s[n].lazy3*_k%mod;
		for(int i=1;i<=top;i++) s[n].lazy1[i]+=add[i];
		return;
	}
	down(n);
	int mid=(s[n].l+s[n].r)>>1;
	if(l<=mid) times(ls,l,r,k,_k);
	if(mid<r) times(rs,l,r,k,_k);
	up(n);
}

inline int query(int n,int l,int r) {
	if(s[n].l>=l&&s[n].r<=r) return s[n].val;
	down(n);
	int mid=(s[n].l+s[n].r)>>1,res=0;
	if(l<=mid) res=(res+query(ls,l,r))%mod;
	if(mid<r) res=(res+query(rs,l,r))%mod;
	return res;
}

signed main()
{
//	freopen("in.txt","r",stdin);
	a=read();
	mod=read();
	pp=get_phi(mod);
	int opt,x,y,z;
	get(mod);
	for(int i=1;i<=a;i++) {
		q[i]=read();
		for(int j=1;j<=top;j++) {
			while(q[i]%p[j]==0) {
				q[i]/=p[j];
				t[i][j]++;
			}
		}
	}
	build(1,1,a);
	b=read();
	for(int i=1;i<=b;i++) {
		opt=read();
		x=read();
		y=read();
		if(opt==1) {
			z=read();
			if(z==1) continue;
			int _z=z;
			for(int j=1;j<=top;j++) {
				add[j]=0;
				while(_z%p[j]==0) _z/=p[j],add[j]++;
			}
			times(1,x,y,z,_z);
		}
		else if(opt==2) div(1,x,y);
		else printf("%lld\n",query(1,x,y));
	}
    return 0;
}
posted @ 2020-12-01 15:11  RedreamMer  阅读(166)  评论(0编辑  收藏  举报