cf#338-D. Multipliers-数论-费马小定理

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

D. Multipliers
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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 test(s)
input
2
2 3
output
36
input
3
2 3 2
output
1728
Note

In the first sample n = 2·3 = 6. The divisors of 6 are 123 and 6, their product is equal to 1·2·3·6 = 36.

In the second sample 2·3·2 = 12. The divisors of 12 are 12346 and 121·2·3·4·6·12 = 1728.


 题意很简洁


给你一个数的所有质因数,然后让你求出这个数所有因数的乘积

有几个知识:
1、
一个数的素因子为p1,p2,p3.....其数量为t[1],t[2]....t[n],共 kind种素数
那么这个数的因子个数为 sum=(t[1]+1)*(t[2]+1)*****(t[n]+1);    //这个很好推,就是把每个因子看成是kind个素因子的乘积,

每次一个素因子的次方为 0 1 2 ...t[i]共(t[i]+1)种

那么我们要求所有因数的乘积ans,我们先求每个素因子对这个ans的贡献:
显然,如果i是这个数的素因子, 那么其贡献可以这样计算,先算出除去这个因子外,其他因子构成的所有情况,每个情况下,分别乘上i^0,i^1,i^2.....i^t[i], 再乘起来,就得到了 i 参与的所有因子的乘积了.
那么,其他因子构成的所有情况= sum/(t[i]+1);
              i^0,i^1,i^2.....i^t[i]=i^((t[i]+1)*t[i]/2);

那么 i 的贡献就是   【i^((t[i]+1)*t[i]/2)】^ sum/(t[i]+1)  ==》 i^【(t[i]+1)*t[i]/2*sum/(t[i]+1)】
 ==》 i^(sum*t[i]/2); 这就好办了

2、根据费马小定理   :假如p是素数,且a与p互质,那么a^(p-1) = 1 (mod p)。
由此可以推得 a^x%p==> a^(x%(p-1))%p
简单说下,因为a^(p-1) =1,那么 假设x/(p-1)=k, a^x= a^(k(p-1)+x%(p-1)) = (a^(p-1)^k) * a^(x%(p-1))= 1^k*  a^(x%(p-1))

那么我们要求的  i^x%mod ,   这里的指数x是很大的,
根据上面的推论,原式= i^(x%(p-1)) %mod ,也就是我们求x的过程% (p-1)就可以了
但是我们会发现,x=sum*t[i]/2;  也就是最后 还有一步除2, 这个 sum原本一定是偶数,可以除二,但是经过取模后不一定是偶数,t[i]也不一定是偶数,这里的指数似乎会出问题,  怎么办呢?
我们要想在%(p-1)之后的sum是2的倍数,我们可以 在求sum取模的过程去模 2(p-1), 显然sum在取模前是偶数,如果对2(p-1)取模后,必然也是偶数(偶数-k*偶数=偶数),这样我们就 保证了指数的正确性了!
当然这样最终得到的X还需要去mod(p-1)


简单说一下对2(p-1)取模会不会影响答案:
首先x/2=k*mod+r  ==》 x/2%mod=r; 
x/2= k*mod+r 
x=2*k*mod+2*r
a%(2mod)=2*r    ==》 a%(2mod)/2=r
 


那么到此,问题就解决了   


我们梳理一下步骤:

1、求sum =(t[1]+1)(t[2]+1).....(t[n]+1)%(2(mod-1))

2、对每个i,ans=ans* i^( sum*t[i]/2%(mod-1) ) %mod;




 
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include<stack>
using namespace std; 
  __int64 mod=1e9+7;
__int64 pow_m(__int64 a,__int64 b,__int64 c)
{
	__int64 ans=1; 
	__int64 tmp=a; 
	while(b)
	{ 	
		if (b&1) 
			ans=ans*tmp%c;    //不可以写 ans=ans*ans%c 结果会变
		tmp=tmp*tmp%c;
		b=b>>1;
	} 
	return ans;	 
}

__int64 tm[200005];
int main()
{ 
  int n;
  __int64 i,x;
  cin>>n; 
  __int64 j;
  for(  j=1;j<=n;j++)
  {
	  scanf("%I64d",&x);  
	  tm[x]++;
  }
  __int64 sum=1;
  for (i=1;i<=200000;i++)
	  if (tm[i])  sum=sum*(tm[i]+1)%(2*mod-2);
  
  __int64 ans=1;
  for (i=1;i<=200000;i++)
	  if (tm[i])  ans=ans*pow_m(i, sum*tm[i]/2%(mod-1) ,mod)%mod;  

  printf("%I64d\n",ans%mod);
  return 0;
} 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值