bzoj3560: DZY Loves Math V
这个题不应该想不到的啊
考虑对于每个质因数分别计算答案,最后再乘起来
那么每个答案就是phi(p^(sigema(1~n)i bi)) bi表示这个位置用了多少当前质因数,显然我们可以算出bi的上界ci,即在ai中pi出现了几次
而函数值非常简单,就是p^(k-1)*(p-1),而根据乘法分配律可以得到答案其实就是product(1~n)i (sigema(1~ci)j p^j)*(p-1)/p
因为一个数的因数个数不会超过30,直接暴力算就可以了
还有一个问题,就是phi(1)的情况,我们可以对柿子进行一点操作令它合法,变成((sigema(1~ci)j p^j)-1)*(p-1)/p+1就好了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const int _=1e2; const int maxn=1e5+_; const int maxp=10+5; const LL mod=1e9+7; LL quick_pow(LL A,int p) { LL ret=1; while(p!=0) { if(p%2==1)ret=ret*A%mod; A=A*A%mod;p/=2; } return ret; } struct node{int p,c;}p[maxp*maxn];int plen; bool cmp(node n1,node n2){return n1.p<n2.p;} void divi(int n,int w) { for(int i=2;i*i<=n;i++) if(n%i==0) { p[++plen].p=i; while(n%i==0)n/=i,p[plen].c++; } if(n!=1)p[++plen].p=n,p[plen].c=1; } int a[maxn]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); divi(a[i],i); } sort(p+1,p+plen+1,cmp); LL ans=1; int l,r=0; while(l<=plen) { l=r+1; while(r<plen&&p[r+1].p==p[l].p)r++; LL num=1; for(int i=l;i<=r;i++) { LL sum=0,d=1; for(int j=0;j<=p[i].c;j++) { sum+=d;if(sum>=mod)sum-=mod; d=d*p[l].p%mod; } num=num*sum%mod; } num=(num+mod-1)*(p[l].p-1)%mod*quick_pow(p[l].p,mod-2)%mod+1; ans=ans*num%mod; } printf("%lld\n",ans); return 0; }
pain and happy in the cruel world.