Luogu 3934 Nephren Ruq Insania

Ynoi2016 炸脖龙重题了。

BZOJ 5394。

首先是扩展欧拉定理:

一开始傻掉了……递归的层数和区间长度无关……也就是说我们每一次直接暴力递归求解子问题一定不会超过$logP$层,因为当模数变成$1$了的时候,不管怎么乘方都不会再变化了。

然后要注意$b < \phi (P)$的情况,在快速幂的时候判断一下,如果超过了$\phi (P)$,那么就再加上一个$P$。

对于区间修改,树状数组或者线段树均可,每一层直接查询。

一共有不超过$logP$层,每一层有$logn$的开销查询元素,所以最后的复杂度是$O(Maxn + qlogP * logn)$。

另外,BZOJ上要把$pri$开成一半才不会爆空间……

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

const int N = 5e5 + 5;
const int M = 2e7 + 5;
const int Maxn = 2e7;

int n, qn, pCnt = 0, pri[M / 2];
ll a[N], phi[M];
bool np[M];

template <typename T>
inline void read(T &X) {
    X = 0; char ch = 0; T op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}    

inline void sieve() {
    phi[1] = 1;
    for(int i = 2; i <= Maxn; i++) {
        if(!np[i]) pri[++pCnt] = i, phi[i] = i - 1;
        for(int j = 1; j <= pCnt && pri[j] * i <= Maxn; j++) {
            np[i * pri[j]] = 1;
            if(i % pri[j] == 0) {
                phi[i * pri[j]] = phi[i] * pri[j];
                break;
            }
            phi[i * pri[j]] = phi[i] * (pri[j] - 1);
        }
    }
}

namespace Bit {
    ll s[N];
    
    #define lowbit(p) (p & (-p))
    
    inline void modify(int p, ll v) {
        for(; p <= n; p += lowbit(p))
            s[p] += v;
    }
    
    inline ll query(int p) {
        ll res = 0;
        for(; p > 0; p -= lowbit(p))
            res += s[p];
        return res;
    }
    
} using namespace Bit;

inline ll fpow(ll x, ll y, ll P) {
    ll res = 1; bool tag = 0, tagx = 0;
    for(; y > 0; y >>= 1) {
        if(y & 1) {
            res = res * x;
            tag |= tagx;
            if(res >= P) res %= P, tag = 1;
        }
        if(x >= P) x %= P, tagx = 1;
        x = x * x;
        if(x >= P) x %= P, tagx = 1;
    }
    return res + (tag ? P : 0);
}

ll solve(int x, int y, ll P) {
    if(P == 1) return 1;
    if(x > y) return 1;
    ll val = a[x] + query(x), cur = solve(x + 1, y, phi[P]);
    return fpow(val, cur, P);
}

int main() {
    sieve();
    read(n), read(qn);
    for(int i = 1; i <= n; i++) read(a[i]);
    for(int op, x, y; qn--; ) {
        read(op), read(x), read(y);
        if(op == 1) {
            ll v; read(v);
            modify(x, v), modify(y + 1, -v);
        } else {
            ll P; read(P);
            printf("%lld\n", solve(x, y, P) % P);
        }
    }
    return 0;
}
View Code

 

posted @ 2018-09-27 20:09  CzxingcHen  阅读(365)  评论(0编辑  收藏  举报