Cf div2 338 D [费马小定理]

题目连接

http://codeforces.com/contest/615/problem/D

Description

Ayrat has number n, represented as it’s prime factorization pi of size m, i.e. n = p1·p2·…·pm. Ayrat got secret information that that the product of all divisors of n taken modulo 109 + 7 is the password to the secret data base. Now he wants to calculate this value.

Input

The first line of the input contains a single integer m (1 ≤ m ≤ 200 000) — the number of primes in factorization of n.
The second line contains m primes numbers pi (2 ≤ pi ≤ 200 000).

Output

Print one integer — the product of all divisors of n modulo 109 + 7.

Sample Input

3
2 3 2

Sample Output

1728

题意

给出一个数的所有素因子,问这个数所有因子的积是多少,结果对1e9+7取余。

题解

可以看成是组合问题,例如 2^3 3^2 5^2,这是一个数的所有素因子,那出现2的因子就是2^1,2^2,2^3依次和其他所有其他素因子组合,对于素因子3就有3种选择,0,1,2。对于5也有3种选择,0,1,2。2的1次幂,2次幂,3次幂与这些数组合,高斯公式求和…。(3+1)* 3/2 * (2+1)*(2+1),这个就是2的幂次,因为幂次可能特别大,用费马小定理处理下,mod(1e9+6),然后在快速幂。 //pow1代表素因子2的个数
可以注意到,所有的数都要算num+1的积的,即p= (pow2+1)* (pow3+1)……* (pown+1) ,这个p在计算每个素因子的幂次的时候都要用到,我们可以提前算出来,这样就不用前缀+后缀那么算了。然后在 * pown/2//素因子n的个数。
其中很坑的地方,mut=mut* (it->second+1)%(2* (MOD-1)) 我感觉是我不用前缀和后缀才会出现这样奇怪的问题,为什么是mod二倍呢,后来看了别人代码,想了很久才明白。因为可能出现比如 22 mod 12 然后是* 2 /是4.。。这样按原先算,就是10*2/4mod(MOD)=5,但是按后一种方法算是22 *2/4mod(MOD)=11,为什么会这样呢?因为第一步正常取模以后的值是小于MOD的,如果后面的操作总体是<1的 即2/4是小于1的,但如果总体是大于1的就没有问题,因为反正都是算出来大于MOD在取余的,那相当于就是在给一个已经小于MOD的值做操作,这样是错误的。但其实我们应该是开始有一个大于MOD的值,进行一系列操作以后仍大于MOD在取余,得到我们的答案。

代码

#include<bits/stdc++.h>
#define ll  long long
using namespace std;
const ll  MOD=1e9+7;
ll  fastpow(ll  a,ll  b,ll  mod)  //快速幂
{
    ll res=1;
    ll x=b;
    while(a>0)
    {
        if(a&1)res=((res%MOD)*(x%MOD))%MOD;
        x=((x%MOD)*(x%MOD))%MOD;
        a/=2;
    }
    return res;
}


int main()
{

    ll n;
    scanf("%I64d",&n);
    map<long long,long long>s;
    ll sum=0, mut=1;
    for(ll i=0;i<n;i++)
    {
        ll v;
        scanf("%I64d",&v);
        s[v]++;  //统计素因子个数
    }

    map<long long,long long>::iterator it=s.begin();
    for(;it!=s.end();it++) //费马小定理处理幂次
    {
        mut=mut*(it->second+1)%(2*(MOD-1));//最坑的地方,%(2*(MOD-1))具体解释看上面
    }
    ll ans=1;
    it=s.begin();
    for(;it!=s.end();it++)
    {
        ll x=it->first;
        ll kk=it->second; 
        ll y=mut*kk/2%(MOD-1);  //处理幂次
        ll t=fastpow(y,x,1e9+7)%MOD;

        ans=((ans%MOD)*(t%MOD))%MOD;
    }

    printf("%I64d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值