4869: [Shoi2017]相逢是問候

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。
1n50000,1m50000,1p100000000,0<c<p,0ai<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<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<cmath>
#include<set>
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;
}
發佈了730 篇原創文章 · 獲贊 20 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章