1 条题解

  • 6
    @ 2021-10-8 11:33:51

    长度为 11 时,合并后的每项次数分别为 11

    长度为 22 时,合并后的每项次数分别为 1,11,1

    长度为 33 时,合并后的每项次数分别为 1,2,11,2,1

    长度为 44 时,合并后的每项次数分别为 1,3,3,11,3,3,1

    由数学归纳法可以得到,最后的每项次数分别为 $\binom {n-1} 0,\binom {n-1} 1,\binom {n-1} 2,\cdots,\binom {n-1} {n-1}$

    所以为了求解 $\displaystyle \prod_{i=1}^n a_i^{\binom {n-1}i}\bmod P$ ,只需要对组合数模 (P1)(P-1) ,最后跑快速幂合并即可


    由于组合数的模数不是质数,不能直接由逆元推得,可以考虑使用 exLucas,不过那玩意儿难码。

    考虑到组合数的递推式 (n1i)=nii(n1i1)\binom{n-1}i={n-i\over i}\binom {n-1}{i-1} ,而结果恒为整数。故实际上组合数递推过程中除去的结果一定为剩余部分的一个因子

    考虑 P1=109+6=(5×108+3)×2P-1=10^9+6=(5\times 10^8+3)\times 2

    将组合数分为三个部分维护:22 的指数、5×108+35\times 10^8+3 的指数和剩余的部分

    作乘法的时候,前两者为相加,后者为乘积

    作除法的时候,前两者为相减,后者为乘上逆元(逆元直接取 φ(P1)=5×108+2\boldsymbol \varphi(P-1)=5\times 10^8+2 指数即可)

    查询值的时候暴力跑一下快速幂即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<ll, ll> pii;
    typedef double db;
    #define fi first
    #define se second
    
    const int P=1e9+7;
    inline ll fpow(ll a, ll x, ll mod) { ll ans=1; for(;x;x>>=1,a=a*a%mod) if(x&1) ans=ans*a%mod; return ans; }
    
    int p[2]={2, P>>1}, phi=p[1]-1;
    struct exnum{
        int x, cnt[2];
        exnum() { x=0; cnt[0]=cnt[1]=0; }
        exnum(int val_) {
            cnt[0]=cnt[1]=0;
            for(int i=0; i<2; ++i)
                while(val_%p[i]==0)
                    ++cnt[i], val_/=p[i];
            x=val_;
        }
        exnum(int x_, int c0_, int c1_):x(x_) { cnt[0]=c0_; cnt[1]=c1_; }
        inline int val() const { return fpow(p[0], cnt[0], P-1)*fpow(p[1], cnt[1], P-1)%(P-1)*x%(P-1); }
    };
    inline exnum operator * (const exnum &a, const exnum &b) { return exnum((ll)a.x*b.x%(P-1), a.cnt[0]+b.cnt[0], a.cnt[1]+b.cnt[1]); }
    inline exnum operator / (const exnum &a, const exnum &b) { return exnum((ll)a.x*fpow(b.x, phi-1, P-1)%(P-1), a.cnt[0]-b.cnt[0], a.cnt[1]-b.cnt[1]); }
    inline exnum operator * (const exnum &a, int b) { return a*exnum(b); }
    inline exnum operator / (const exnum &a, int b) { return a/exnum(b); }
    
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        int n, res=1;
        cin>>n;
        exnum comb(1);
        for(int i=1, a; i<=n; ++i) {
            cin>>a;
            res=(ll)res*fpow(a, comb.val(), P)%P;
            if(i<n) comb=comb*(n-i)/i;
        }
        cout<<res;
        cout.flush();
        return 0;
    }
    
    • @ 2023-7-1 21:54:37

      我还不太会

    • @ 2024-7-12 16:59:18

      都使用快速幂?快速幂要靠递归算法

信息

ID
87
时间
1000ms
内存
256MiB
难度
5
标签
递交数
117
已通过
44
上传者