1. 程式人生 > 其它 >P3747 [六省聯考 2017] 相逢是問候 題解

P3747 [六省聯考 2017] 相逢是問候 題解

Description

Luogu傳送門

Solution

不打算詳細寫了,簡單寫寫做題歷程。

一看題,顯然要用線段樹維護,但是 \(c^{a_i}\) 這東西怎存??

於是看了一眼標籤,發現 尤拉公式 這個東西,於是想到尤拉定理。

再聯想到區間開方的操作只有前 \(\sqrt n\) 次有用。發現這東西只有前 \(\log\) 次操作有用,所以直接暴力維護即可。

另外 \(c^x\) 次方要提前預處理出來,不然會多一個 \(\log\)

其他的見程式碼吧,有一點註釋。

這道題的思路還是非常有啟發性的。

Code

#include <bits/stdc++.h>
#define ll long long
#define ls rt << 1
#define rs rt << 1 | 1

using namespace std;

namespace IO{
    inline int read(){
        int x = 0;
        char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
        return x;
    }

    template <typename T> inline void write(T x){
        if(x > 9) write(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace IO;

const int N = 5e4 + 10;
int n, m, mod, c;
int a[N][60];

namespace Prework{
    int c1[60][1 << 15], c2[60][1 << 15], phi[60];
    int totp = 0;

    inline int add(int x) {return x >= mod ? x -= mod : x;}
    inline int times(ll x, int mod) {return x >= mod ? (x % mod + mod) : x;}
    inline int power(int x, int i) {return times(1ll * c1[i][x & ((1 << 15) - 1)] * c2[i][x >> 15], phi[i]);}

    //單點計算 phi
    inline int calc_phi(int x){
        int res = x;
        for(int i = 2; i * i <= x; ++i){
            if(x % i == 0){
                res = res / i * (i - 1);
                while(x % i ==0) x /= i;
            }
        }
        if(x > 1) res = res / x * (x - 1);
        return res;
    }

    //預處理 (c^x) % phi[i],分成兩半(更快),對於每個 phi[i] 都要預處理
    inline void calc_c(){
        for(int i = 0; i <= totp; ++i){
            c1[i][0] = c2[i][0] = 1;
            for(int j = 1; j < (1 << 15); ++j)
                c1[i][j] = times(1ll * c1[i][j - 1] * c, phi[i]);
            c2[i][1] = times(1ll * c1[i][(1 << 15) - 1] * c, phi[i]);
            for(int j = 2; j < (1 << 15); ++j)
                c2[i][j] = times(1ll * c2[i][j - 1] * c2[i][1], phi[i]);
        }
    }

    //預處理出 a[i] 每次操作之後數是多少
    inline int calc(int x, int cnt, int i){
        if(!cnt) return times(x, phi[i]);
        if(i == totp) return c ? 1 : 0;
        return power(calc(x, cnt - 1, i + 1), i);
    }

    //同上
    inline void prework(){
        phi[0] = mod;
        while(phi[totp] > 1) totp++, phi[totp] = calc_phi(phi[totp - 1]);
        calc_c();
        for(int i = 1; i <= n; ++i){
            a[i][0] = read();
            for(int j = 1; j <= totp + 1; ++j){
                a[i][j] = calc(a[i][0], j, 0) % mod;
            }
            a[i][0] %= mod;
        }
    }
}
using namespace Prework;

namespace Segment_Tree{
    int sum[N << 2], mins[N << 2];//sum 記錄區間和,mins 記錄修改次數

    inline void pushup(int rt){
        mins[rt] = min(mins[ls], mins[rs]);
        sum[rt] = add(sum[ls] + sum[rs]);
    }

    inline void build(int l, int r, int rt){
        if(l == r){
            sum[rt] = a[l][0];
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid, ls);
        build(mid + 1, r, rs);
        pushup(rt);
    }

    inline void update(int L, int R, int l, int r, int rt){
        if(mins[rt] > totp) return;
        if(l == r) return sum[rt] = a[l][++mins[rt]], void();
        int mid = (l + r) >> 1;
        if(L <= mid) update(L, R, l, mid, ls);
        if(R > mid) update(L, R, mid + 1, r ,rs);
        pushup(rt);
    }

    inline int query(int L, int R, int l, int r, int rt){
        if(L <= l && r <= R) return sum[rt];
        int mid = (l + r) >> 1;
        int res = 0;
        if(L <= mid) res = add(res + query(L, R, l, mid, ls));
        if(R > mid) res = add(res + query(L, R, mid + 1, r, rs));
        return res;
    }
}
using namespace Segment_Tree;

signed main(){
    n = read(), m = read(), mod = read(), c = read();
    prework();
    build(1, n, 1);
    while(m--){
        int op = read(), l = read(), r = read();
        if(!op) update(l, r, 1, n, 1);
        else write(query(l, r, 1, n, 1)), puts("");
    }
    return 0;
}
\[\_EOF\_ \]

本文來自部落格園,作者:xixike,轉載請註明原文連結:https://www.cnblogs.com/xixike/p/15719856.html