题意:
n<=100000,Ai<=100000;
因为答案可能很大,所以只要输出模1000000007后的值就可以了;
多组数据,所有数据的n的和<=500000;
题解:
挺有意思的一道数论题,虽说比赛的时候并没有推出来就弃疗啦;
首先因为N的质因子都在n的范围内,所以我们可以预处理一些素数啊,最小素因子之类的东西;
然后我们得到了N=p1^t1*p2^t2*p3^t3...pk^tk这种形式的N;
计算约数积,我们考虑对于每个素数单独计算;
N一共有(t1+1)*(t2+1)*...*(tk+1)这么多的约数;
对于一个质因数pi,在每个约数中可能出现pi^0,pi^1,pi^2...,pi^ti这些值,有ti+1种值;
并且它们出现的机会是相同的,所以每种pi^j都出现了Π(tx+1)/(ti+1)次;
直观一些来说,其实就是我们用N的其他所有质因子凑出所有能凑出的数之后,分别用pi^0,pi^1,pi^2...,pi^ti去乘它们,得到Π(tx+1)个约数;
那么pi在约数积中一共就出现了(0+1+2+3+...+ti)*Π(tx+1)/(ti+1)次,枚举pi之后快速幂计算即可;
然而还有一些细节,比如显然pi的指数会爆,那么就用费马小定理mod 1000000007-1即可;
而mod之后除(ti+1)不好处理,那就处理前缀积和后缀积;
至于前面等差数列求和的除二,在极限数据下ti恰好会爆掉int一些,不过开long long再讨论奇偶就可以搞了;
最后一点,如果你TLE了,小心坑爹的多组数据!在多组数据下复杂度可能会不对;
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #define N 110000 #define mod 1000000007 using namespace std; typedef long long ll; int pri[N],fp[N],tot; ll q[N]; int sl[N],sr[N]; bool vis[N]; void init(int n) { int i,j; tot=0; memset(vis,0,sizeof(vis[0])*(n+1)); memset(q,0,sizeof(q[0])*(n+1)); for(i=2;i<=n;i++) { if(!vis[i]) pri[++tot]=i,fp[i]=tot; for(j=1;j<=tot&&pri[j]*i<=n;j++) { vis[pri[j]*i]=1; fp[pri[j]*i]=j; if(i%pri[j]==0) break; } } } int pow(int x,int y) { if(y<0) while(1)puts("fuck"); int ret=1; while(y) { if(y&1) ret=(ll)ret*x%mod; x=(ll)x*x%mod; y>>=1; } return ret; } int main() { int n,i,x,y,ans; while(scanf("%d",&n)!=EOF) { init(n); for(i=1;i<=n;i++) { scanf("%d",&y); if(!y) continue; x=i; while(x!=1) { q[fp[x]]+=y; x/=pri[fp[x]]; } } sl[0]=sr[tot+1]=1; for(i=1;i<=tot;i++) { sl[i]=sl[i-1]*(q[i]+1)%(mod-1); } for(i=tot;i>=1;i--) { sr[i]=sr[i+1]*(q[i]+1)%(mod-1); } for(i=1,ans=1;i<=tot;i++) { y=(q[i]&1?(q[i]+1)/2%(mod-1)*(q[i]%(mod-1)):q[i]/2%(mod-1)*((q[i]+1)%(mod-1)))%(mod-1)*((ll)sl[i-1]*sr[i+1]%(mod-1))%(mod-1); ans=(ll)ans*pow(pri[i],y)%mod; } printf("%d\n",ans); } return 0; }
时间: 2024-11-11 20:51:36