P5431 【模板】乘法逆元 2

快速链接

  • 原题链接
  • 题目大意
  • 输入格式
  • 输出格式
  • 数据范围
  • 解题思路
      • 解法
  • 上代码


原题链接

P5431
AC记录:Accepted

题目大意

给定 n n n 个正整数 a i a_i ai,求它们在模 p p p 意义下的乘法逆元。
由于输出太多不好,所以将会给定常数 k k k,你要输出的答案为:
∑ i = 1 n k i a i \sum^n_{i=1}\frac{k^i}{a_i} i=1naiki
答案对 p p p 取模。

输入格式

第一行三个正整数 n , p , k n,p,k n,p,k,意义如题目描述。
第二行 n n n 个正整数 a i a_i ai,是你要求逆元的数。

输出格式

输出一行一个整数,表示答案。

S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input

6 233 42
1 4 2 8 5 7

S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output

91

H i n t & E x p l a i n \mathbf{Hint\&Explain} Hint&Explain
自己手推吧。

数据范围

对于 30 % 30\% 30%的数据, 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1n105
对于 100 % 100\% 100%的数据, 1 ≤ n ≤ 5 × 1 0 6 , 2 ≤ k < p ≤ 1 0 9 , 1 ≤ a i ≤ p 1≤n≤5\times 10^6,2\le k1n5×106,2k<p109,1aip,保证 p p p 为质数。

解题思路

⚠  警告 此题时间限制仅有550ms! { \color{#FF9100}{\rule[0pt]{2pt}{40pt}} \color{#FFF4E5}{\rule[20pt]{200pt}{20pt}} \kern{-200pt} \color{#FFFFFF}{\rule[0pt]{200pt}{20pt}} \color{orange}{\raisebox{27pt}{\kern{-195pt}{\footnotesize\bf ⚠ 警告}}} \color{black}{\raisebox{7pt}{\kern{-195pt}{\footnotesize\bf 此题时间限制仅有550ms!}}} }  550ms!
出题人还算良心吧,就比乘法逆元 只多了50ms
顺便推销一下我写的乘法逆元的博客。

解法

这次我们要用 阶乘求逆元
我们设 m u l i mul_i muli 为前 i i i 个数字的乘积, i n v m u l i invmul_i invmuli m u l i mul_i muli 的逆元。
而题目里面的式子说是 ∑ i = 1 n k i a i \large\sum\limits^n_{i=1}\frac{k^i}{a_i} i=1naiki,是 k i k^i ki 1 a i \dfrac 1{a_i} ai1 也就是 a i a_i ai 的逆元的乘积。那么如何求单个元素 a i a_i ai 的乘积呢?
我们知道, i n v m u l i = 1 a 1 × a 2 × ⋯ × a i = 1 a 1 × a 2 × ⋯ × a i − 1 × 1 a i invmul_i=\dfrac 1{a_1\times a_2\times\cdots\times a_i}=\dfrac 1{a_1\times a_2\times\cdots\times a_{i-1}}\times\dfrac1{a_i} invmuli=a1×a2××ai1=a1×a2××ai11×ai1,所以我们只要消掉 1 a 1 × a 2 × ⋯ × a i − 1 \dfrac 1{a_1\times a_2\times\cdots\times a_{i-1}} a1×a2××ai11,即乘上 m u l i − 1 mul_{i-1} muli1,就可以求出 a i a_i ai 的逆元。由此可得
1 a i = i n v m u l i × m u l i − 1 \frac1{a_i}=invmul_i\times mul_{i-1} ai1=invmuli×muli1
然后就可以线性求逆元啦。
最后,还有一个优化,就是秦九韶算法,循环时,要 从大到小 循环,而每一次处理答案,只需要把答案乘 k k k 就可以了。
i n v m u l n invmul_n invmuln 可以由费马小定理求出,即 i n v m u l n = ( m u l n ) p − 2 invmul_n=(mul_n)^{p-2} invmuln=(muln)p2

上代码

#include

#define endl '\n'

using namespace std;

#define int long long

int mul[5000010];
int a[5000010];
int n,p,k;

int power(int a,int b,int p)
{
    int tar=1;
    while(b)
    {
        if(b&1)
            tar=(long long)(tar*a)%p;
        a=(long long)(a*a)%p;
        b>>=1;
    }
    return tar;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    /* Code */
    cin>>n>>p>>k;
    mul[0]=1;
    for(int i=1; i<=n; i++)
        cin>>a[i],mul[i]=1ll*mul[i-1]*a[i]%p;
    int invmul=power(mul[n],p-2,p);//算invmul[n]
    int tar=0;
    for(int i=n; i>=1; i--)
    {
        int invai=1ll*invmul*mul[i-1]%p;//求ai的逆元
        tar=1ll*(tar+invai)*k%p;//秦九韶算法
        invmul=(1ll*invmul*a[i])%p;//算invmul[i-1]
    }
    cout<<tar<<endl;
    return 0;
}

完美切题 ∼ \sim

你可能感兴趣的:(洛谷【模板】,洛谷题库题目,算法,c++,动态规划)