bzoj4869

http://www.lydsy.com/JudgeOnline/problem.php?id=4869

终于A了。。。参考了下dalao的代码。。。

拓展欧几里得定理,改了几次就不变了,但是用的时候要在快速幂里判是不是要用。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int n, m, cnt;
ll p, c;
ll phi[N], table[N];
namespace seg // n^x = n^(x % phi[x] + phi[x])
{
    struct data {
        ll ans, mn;
    } tree[N << 2];
    inline ll getphi(ll x)
    {
        ll ret = x, lim = x;
        for(ll i = 2; i * i <= lim; ++i) if(x % i == 0) 
        {
            ret = ret * (i - 1) / i;
            while(x % i == 0) x /= i;
        }
//      printf("ret=%d\n", ret);
        if(x > 1) ret = ret * (x - 1) / x;
        return ret;
    }
    inline ll power(ll x, ll t, ll p, bool &flag)
    {
        bool big = false;
        ll ret = 1; 
        for(; t; t >>= 1) 
        {
            if(t & 1) 
            {
                ret = ret * x ;
                flag |= big | (ret >= p);        
                ret %= p;
            }
            x = x * x; if(x >= p) big = true, x %= p; 
        }
        return ret; 
    }
    ll calc(ll x, int t)
    {
        if(x >= phi[t]) x = x % phi[t] + phi[t];
        for(int i = t - 1; i >= 0; --i) 
        {
            bool flag = false;
            x = power(c, x, phi[i], flag);
            if(flag) x += phi[i];
        }
        return x % phi[0];
    }
    inline void build(int l, int r, int x)
    {
        if(l == r) { 
            tree[x].ans = table[l]; 
            return; 
        }
        int mid = (l + r) >> 1;
        build(l, mid, x << 1); 
        build(mid + 1, r, x << 1 | 1);
        tree[x].ans = (tree[x << 1].ans 
                     + tree[x << 1 | 1].ans) % phi[0];
    } 
    inline void update(int l, int r, int x, int a, int b)
    { //如果这次的幂和上次一样就不变了 
        if(tree[x].mn >= cnt) return;
        if(l > b || r < a) return;
        if(l == r)
        {
            ++tree[x].mn;
            tree[x].ans = calc(table[l], tree[x].mn);
            return;
        }
        int mid = (l + r) >> 1;
        update(l, mid, x << 1, a, b); 
        update(mid + 1, r, x << 1 | 1, a, b);
        tree[x].mn = min(tree[x << 1].mn, 
                         tree[x << 1 | 1].mn);
        tree[x].ans = (tree[x << 1].ans + 
                       tree[x << 1 | 1].ans) % phi[0]; 
    }
    inline ll query(int l, int r, int x, int a, int b)
    {
        if(l > b || r < a) return 0;
        if(l >= a && r <= b) return tree[x].ans % phi[0];
        int mid = (l + r) >> 1, ret = 0;
        ret = (ret + query(l, mid, x << 1, a, b)) % phi[0];
        ret = (ret + query(mid + 1, r, x << 1 | 1, a, b)) % phi[0];
        return ret;    
    } 
} using namespace seg;
int main()
{
    scanf("%d%d%lld%lld", &n, &m, &p, &c);
    phi[0] = p;
    ll P = p;
    while(P != 1) phi[++cnt] = P = getphi(P);
    phi[++cnt] = 1; 
    for(int i = 1; i <= n; ++i) scanf("%lld", &table[i]);
    build(1, n, 1); 
    while(m--)
    {
        int opt, l, r; scanf("%d", &opt);
        if(opt == 0)
        {
            scanf("%d%d", &l, &r); 
            update(1, n, 1, l, r);
        }
        if(opt == 1) 
        {
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, n, 1, l, r));
        }
    }
    return 0;
}
View Code

 

posted @ 2017-05-09 20:13  19992147  阅读(162)  评论(0编辑  收藏  举报