zoukankan      html  css  js  c++  java
  • P5431 【模板】乘法逆元2

    洛谷题目链接

    刚开始做乘法逆元还是有点懵逼的~

    以下式子都在模(p)意义下进行

    我们把式子改一下,变成:$$sumlimits_{i=1}nki imes a_i^{-1}$$

    我们先算出(a_i)的前缀积:$$s[i]=s[i-1] imes a_i$$

    我们发现只要算出每一个前缀积的逆元(t_i),每一个(a_i)的逆元都好求了:$$a_i^{-1}=t_i imes s_{i-1}$$

    那么怎么求每一个前缀积的逆元呢,我们可以先把$t_n运用费马小定理求出来: $$t_n=s_n^{p-2}$$

    再根据:$$t_i=t_{i+1}*a_{i+1}$$

    递推出所有的(t)

    这样就把所有的逆元(O(n))求出来了,我们再把原式变形:$$a_1{-1}k1+a_2{-1}k2+cdots+a_{n-1}{-1}k{n-1}+a_n{-1}kn$$

    [k(a_1^{-1}+k(a_2^{-1}+cdots+k(a_{n-1}^{-1}+a_n^{-1}k))) ]

    我们就可以(O(n))求出答案啦~~~

    接下来是美滋滋的代码时间~~~(必须用快读。。)

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #define int long long
    #define N 5000007
    using namespace std;
    int n,p,k;
    int s[N],a[N],inv_s[N];
    int Read()
    {
    	int fu=1,ret=0;
    	char c=getchar();
    	while(c<'0'||c>'9')
    	{
    		if(c=='-')
    			fu=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9')
    	{
    		ret=(ret<<3)+(ret<<1)+c-'0';
    		c=getchar();
    	}
    	return ret*fu;
    }
    int qpow(int a,int b)
    {
    	int ans=1,res=a;
    	while(b)
    	{
    		if(b&1)
    			ans=(ans*res)%p;
    		res=(res*res)%p;
    		b/=2;
    	}
    	return ans%p;
    }
    signed main()
    {
    	n=Read(),p=Read(),k=Read();
    	s[0]=1;
    	for(int i=1;i<=n;++i)
    	{
    		a[i]=Read();
    		s[i]=(s[i-1]*a[i])%p;
    	}
    	inv_s[n]=qpow(s[n],p-2);
    	for(int i=n-1;i>=1;--i)
    		inv_s[i]=(inv_s[i+1]*a[i+1])%p;
    	int ans=0;
    	for(int i=n;i>=1;--i)
    		ans=((inv_s[i]*s[i-1])%p+ans)*k%p;
    	printf("%lld
    ",(ans+p)%p);
    	return 0;
    }
    
  • 相关阅读:
    18个Java开源CMS系统一览
    冒泡排序
    数据挖掘十大经典算法
    开源Java CMS建站程序推荐
    Oracle
    Oracle Procedure returning Ref Cursor in Entity Framework 4
    Field_II
    SharePoint Video Library
    ORACLE 导入dmp文件
    System.Diagnostics.Process.Start()。它的作用是调用外部的命令
  • 原文地址:https://www.cnblogs.com/yexinqwq/p/11051316.html
Copyright © 2011-2022 走看看