zoukankan      html  css  js  c++  java
  • bzoj4869 [Shoi2017]相逢是问候

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

    【题解】

    发现好像没有办法普通维护。

    给小盆友们江数论的时候江过x^m mod p = x^(m mod phi(p)) mod p

    upd: 这篇文章写的时候我也不知道我自己怎么想的了 好像上面这个有点问题。。但是还是AC了(逃

    下面给出扩展欧拉定理的证明:https://zhuanlan.zhihu.com/p/24902174

    以及,该定理的正确表示$x^m equiv x^{m~mod~phi(p) + [m geq phi(p)] phi(p)}(mod~p)$

    注意当$m < phi(p)$的时候是不用加上$phi(p)$的。

    发现一个数进行phi操作最多log次。

    暴力就行啦qwq

    注意就是phi的那个最后要补一个phi[++pn] = 1。

    为什么呢?因为phi(1) = 1(展开到最后,还要多展开一层(!))

    那么就行啦!

    复杂度不大会分析qwq

    照理性分析可能是log方到log三方之间的啦

    反正跑的……挺快

    upd: 两份代码均已经更正。 感谢Exbilar的提醒。

    # include <stdio.h>
    # include <string.h>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10;
    
    # define RG register
    # define ST static
    
    int n, m, p, c, a[M], phi[M], pn;
    
    inline int pwr(int a, int b, int p, bool &ok) {
        ok = 0;
        int ret = 1;
        while(b) {
            if(b&1) ok |= (1ll * ret * a >= p), ret = 1ll * ret * a % p;
            ok |= (1ll * a * a >= p && b != 1); a = 1ll * a * a % p; 
            b >>= 1;
        }
        return ret;
    }
    
    inline int getphi(int n) {
        int ret = n;
        for (int i=2; i*i<=n; ++i) {
            if(n%i!=0) continue;
            ret = ret/i*(i-1);
            while(n%i==0) n/=i;
        }
        if(n!=1) ret=ret/n*(n-1);
        return ret;
    }
    
    inline int calc(int x, int p) {
        int ret = x; bool ok;
        if(ret >= phi[p]) ret = ret % phi[p] + phi[p];
        while(p--) {
            x = ret;
            ret = pwr(c, x, phi[p], ok);  
            if(ok) ret += phi[p];
        }
        return ret % phi[0];
    }
    
    namespace SMT {
        # define ls (x<<1)
        # define rs (x<<1|1) 
        int v[M], tms[M];
        inline void build(int x, int l, int r) {
            if(l==r) {
                v[x] = a[l] % phi[0];
                tms[x] = 0; 
                return ;
            }
            int mid = l+r>>1;
            build(ls, l, mid);
            build(rs, mid+1, r);
            v[x] = (v[ls]+v[rs])%phi[0];
            tms[x] = min(tms[ls], tms[rs]);
        }
        inline void change(int x, int l, int r, int L, int R) {
            if(tms[x] >= pn) return;
            if(l == r) {
                tms[x] ++;
                v[x] = calc(a[l], tms[x]);
                return ;
            }
            int mid = l+r>>1;
            if(L <= mid) change(ls, l, mid, L, R);
            if(R > mid) change(rs, mid+1, r, L, R);
            v[x] = (v[ls]+v[rs])%phi[0];
            tms[x] = min(tms[ls], tms[rs]);
        }
        inline int query(int x, int l, int r, int L, int R) {
            if(L <= l && r <= R) return v[x];
            int mid = l+r>>1, re=0;
            if(L <= mid) re += query(ls, l, mid, L, R);
            if(R > mid) re += query(rs, mid+1, r, L, R);
            return re%phi[0];
        }
        # undef ls
        # undef rs
    }
    
    int main() {
        scanf("%d%d%d%d", &n, &m, &p, &c);
        for (int i=1; i<=n; ++i) scanf("%d", a+i); 
        phi[0] = p; 
        while(p != 1) {
            int t = getphi(p);
            phi[++pn] = t;
            p = t;
        }
        phi[++pn] = 1;
        SMT::build(1, 1, n); 
        int opt, l, r;
        while(m--) {
            scanf("%d%d%d", &opt, &l, &r);
            if(opt==0) SMT::change(1, 1, n, l, r); 
            else printf("%d
    ", SMT::query(1, 1, n, l, r));
        }
        return 0;
    }
    View Code

    我们发现我们可以把快速幂的一个log强行压掉 这样就会快很多啦qwq

    部分代码实现by zhouyi

    # include <stdio.h>
    # include <string.h>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10;
    
    # define RG register
    # define ST static
    
    int n, m, p, c, a[M], phi[M], pn;
    int pws[27][M][2]; 
    bool pwk[27][M][2];
    inline int pwr(int a, int b, int p, bool &ok) {
        ok = 0;
        int ret = 1;
        while(b) {
            if(b&1) ok |= (1ll * ret * a >= p), ret = 1ll * ret * a % p;
            ok |= (1ll * a * a >= p && b != 1); a = 1ll * a * a % p; 
            b >>= 1;
        }
        return ret;
    }
    
    inline int getphi(int n) {
        int ret = n;
        for (int i=2; i*i<=n; ++i) {
            if(n%i!=0) continue;
            ret = ret/i*(i-1);
            while(n%i==0) n/=i;
        }
        if(n!=1) ret=ret/n*(n-1);
        return ret;
    }
    
    inline int pwrb(int b, int p, bool &ok){
        p = min(p, pn); ok = 0;
        ok |= pwk[p][b & 16383][0];
        ok |= pwk[p][b >> 14][1];
        ok |= (1ll * pws[p][b & 16383][0] * pws[p][b >> 14][1] >= phi[p]);
        return 1ll * pws[p][b & 16383][0] * pws[p][b >> 14][1] % phi[p];
    }
    inline int calc(int x, int p) {
        int ret = x; bool ok;
        if(ret >= phi[p]) ret = ret % phi[p] + phi[p];
        while(p--) {
            x = ret;
            ret = pwrb(x, p, ok); 
            if(ok) ret += phi[p]; 
        }
        return ret % phi[0];
    }
    
    namespace SMT {
        # define ls (x<<1)
        # define rs (x<<1|1) 
        int v[M], tms[M];
        inline void build(int x, int l, int r) {
            if(l==r) {
                v[x] = a[l] % phi[0];
                tms[x] = 0; 
                return ;
            }
            int mid = l+r>>1;
            build(ls, l, mid);
            build(rs, mid+1, r);
            v[x] = (v[ls]+v[rs])%phi[0];
            tms[x] = min(tms[ls], tms[rs]);
        }
        inline void change(int x, int l, int r, int L, int R) {
            if(tms[x] >= pn) return;
            if(l == r) {
                tms[x] ++;
                v[x] = calc(a[l], tms[x]);
                return ;
            }
            int mid = l+r>>1;
            if(L <= mid) change(ls, l, mid, L, R);
            if(R > mid) change(rs, mid+1, r, L, R);
            v[x] = (v[ls]+v[rs])%phi[0];
            tms[x] = min(tms[ls], tms[rs]);
        }
        inline int query(int x, int l, int r, int L, int R) {
            if(L <= l && r <= R) return v[x];
            int mid = l+r>>1, re=0;
            if(L <= mid) re += query(ls, l, mid, L, R);
            if(R > mid) re += query(rs, mid+1, r, L, R);
            return re%phi[0];
        }
        # undef ls
        # undef rs
    }
    
    int main() {
        scanf("%d%d%d%d", &n, &m, &p, &c);
        for (int i=1; i<=n; ++i) scanf("%d", a+i); 
        phi[0] = p; 
        while(p != 1) {
            int t = getphi(p);
            phi[++pn] = t;
            p = t;
        }
        phi[++pn] = 1;
        for(int i=0; i<=pn; ++i) {
            bool ok;
            int j = pwr(c, 16384, phi[i], ok);
            pws[i][0][0] = pws[i][0][1] = 1;
            pwk[i][0][0] = 0, pwk[i][0][1] = 0;
            for(int k=1; k<16384; k++) 
                pwk[i][k][0] = pwk[i][k-1][0] | (1ll * pws[i][k-1][0] * c >= phi[i]),
                pws[i][k][0] = 1ll * pws[i][k-1][0] * c % phi[i],
                pwk[i][k][1] = pwk[i][k-1][1] | (ok || (1ll * pws[i][k-1][1] * j >= phi[i])),
                pws[i][k][1] = 1ll * pws[i][k-1][1] * j % phi[i]; 
        }
        
        SMT::build(1, 1, n); 
        int opt, l, r;
        while(m--) {
            scanf("%d%d%d", &opt, &l, &r);
            if(opt==0) SMT::change(1, 1, n, l, r); 
            else printf("%d
    ", SMT::query(1, 1, n, l, r));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    pytest框架
    Zabbix第九章(zabbix自定义item)
    Zabbix第七章(Zabbix监控本地)
    Zabbix第五章(配置zabbix的语言)
    Zabbix第四章(zabbix-server安装)
    Zabbix第二章(下载)
    Zabbix第一章(简介)
    线性筛
    Eratosthenes筛法
    质数判定
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj4869.html
Copyright © 2011-2022 走看看