4869: [Shoi2017]相逢是问候
Time Limit: 40 Sec Memory Limit: 512 MB
Submit: 440 Solved: 124
[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独家拥有在线测评使用权
拿出求幂大法的式子大讨论一发
ca mod p=ca mod ϕ(p)+ϕ(p) mod p
cca mod p=cca mod ϕ(ϕ(p))+ϕ(ϕ(p)) mod ϕ(p)+ϕ(p) mod p
后续展开类似 ……………
注意到对于任意的 p ,不断令 p=ϕ(p) ,期望 log 次以后就有 p=1
因此对于任意位置的数,当修改操作达到一定程度时,再修改也不会改变这个数的值了
注意这个存 ϕ 的数组需要多放一个 1
因为要多展开一层让最上面的幂次为 ca mod 1 之后才达到定值
理论复杂度为 O(nlognlog2p) 级别的实际显然远没有这么糟糕
求幂大法注意判断不用再加 ϕ 的情形
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 5E4 + 5;
typedef long long LL;
int n,m,p,c,tot,A[maxn],B[maxn],C[maxn];
LL sum[maxn],s[maxn];
set <int> st;
stack <int> stk;
set <int> :: iterator it;
inline int ksm(LL x,int y,LL Mod,bool &bo)
{
LL ret = 1; bo = 0;
for (; y; y >>= 1)
{
if (y & 1)
{
bo |= ((ret *= x) >= Mod);
ret %= Mod;
}
bo |= ((x *= x) >= Mod);
x %= Mod;
}
return ret;
}
inline void Modify(int k)
{
LL delta = -B[k]; bool bo = 0; ++C[k];
if (C[k] > tot) {stk.push(k); return;}
int now = C[k] == 1 ? A[k] : ksm(c,A[k],s[C[k]],bo);
if (bo) now += s[C[k]];
for (int i = C[k] - 1; i > 1; i--)
{
now = ksm(c,now,s[i],bo);
if (bo) now += s[i];
}
now = ksm(c,now,p,bo); delta += now; B[k] = now;
for (int i = k; i <= n; i += i&-i) sum[i] += delta;
}
inline void Find(int x)
{
s[++tot] = x;
if (x == 1) return;
int Sqrt = sqrt(x),phi = 1;
for (int i = 2; i <= Sqrt; i++)
{
if (x % i != 0) continue;
phi *= (i - 1); x /= i;
while (x % i == 0) x /= i,phi *= i;
}
if (x > 1) phi *= (x - 1); Find(phi);
}
inline int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getint(); m = getint();
p = getint(); c = getint();
Find(p); s[++tot] = 1;
for (int i = 1; i <= n; i++)
{
A[i] = B[i] = getint(); st.insert(i);
for (int j = i; j <= n; j += j&-j) sum[j] += 1LL * A[i];
}
st.insert(n + 1);
while (m--)
{
int typ = getint(),l,r;
l = getint(); r = getint();
if (!typ)
{
for (it = st.lower_bound(l); (*it) <= r; it++)
Modify(*it);
while (!stk.empty()) st.erase(stk.top()),stk.pop();
}
else
{
LL Ans = 0;
for (int i = r; i > 0; i -= i&-i) Ans += sum[i];
for (int i = l - 1; i > 0; i -= i&-i) Ans -= sum[i];
Ans %= p; printf("%d\n",(int)(Ans + p) % p);
}
}
return 0;
}