jzoj5636 [NOI2018 simulation 4.7] power (extended Euler's theorem, the nature of phi)

Description

Given a positive integer m<=1e9 and n numbers, n<=1e5, q queries, q<=1e5, each time the power value of a certain interval [l, r] is asked:
that is a l a l + 1 a l + 2... a r %m

???

Extended Euler's theorem is suitable for this kind of exponentiation and modulo. The
write picture description here
first one can actually be combined with the following two, and then remove gcd!=1 below.
which is
a b mod p =
1. If b < p h i ( p ) , a^b
2. If b >= p h i ( p ) a b mod p h i ( p ) + p h i ( p )
The specific proof can be found online, so I won't write it here.Will not

Then we can find that every time he is asked, his modulus will continue to take phi, then when taking phi, the odd number will become an even number, and the even number will be halved, so there will only be 2 log m times to 1 in the end. That is to say, the phi of a number is continuously taken, and the number of times is only 2 * log m times.

When l=r or p=1, you can directly return.
Then to solve the problem of b, we found that to find the current b, we only need to find the first 1 in the sequence, and no statistics are needed after this. Then the front is at least 2, which is an exponential growth of the index, and it is very fast (constant time) to judge whether it exceeds p.
In this way, the total complexity is n log^2 n, with some small constants, and the time limit is also opened for 4.5s.

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
typedef double db;
const ll N=1e5+10;
ll n,m,w[N],nx[N],q;
ll nphi[110];
ll min(ll a,ll b) {return a>b?b:a;}
ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);}
ll ksm(ll a,ll b) {
    if (b==0) return 1; if (b==1) return a;
    ll t=ksm(a,b>>1);
    if ((db)t*t*ksm(a,b&1)>1e9) return 1e9+1;
    return t*t*ksm(a,b&1);
}

ll dmksm(ll a,ll b,ll mo) {
    if (b==0) return 1%mo;
    if (b==1) return a%mo;
    ll t=dmksm(a,b>>1,mo);
    return t*t%mo*dmksm(a,b&1,mo)%mo;
}

ll phi(ll x) {
    ll ret=1;
    for (int i=2; i*i<=x; i++) if (x%i==0) {
        int cs=0; while (x%i==0) x/=i,cs++;
        ret=ret*ksm(i,cs-1) * (i-1);
    }
    if (x!=1) ret*=(x-1);
    return ret;
}

ll get(ll l,ll r) {
    r=max(l,min(r,nx[l]-1));
    ll t=w[r];
    for (int i=r-1; i>=l; i--) {
        t=ksm(w[i],t); if (t>1e9) return 1e9+1;
    }
    return t;
}

ll f(ll l,ll r,ll mc) {
    ll mo=nphi[mc];
    if (mo==1 || l==r) return w[l]%mo;
    ll p=get(l+1,r);
    if (p>nphi[mc]) return dmksm(w[l],f(l+1,r,mc+1)+nphi[mc+1],nphi[mc]);
    else return dmksm(w[l],p,nphi[mc]);
}

int main() {
    freopen("power.in","r",stdin);
    freopen("power.out","w",stdout);
    cin>>n>>m;
    for (int i=1; i<=n; i++) scanf("%lld",&w[i]);
    nx[n+1]=n+1;
    for (int i=n; i; i--) nx[i]=w[i]!=1?nx[i+1]:i;
    ll tmp=m; for (int i=1; i<=100; i++,tmp=phi(tmp)) nphi[i]=tmp;
    cin>>q;
    for (int i=1;i<=q;i++) {
        int l,r; scanf("%d %d",&l,&r);
        printf("%lld\n",f(l,r,1));
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325416948&siteId=291194637