1. 程式人生 > >bzoj3560: DZY Loves Math V

bzoj3560: DZY Loves Math V

nod print bzoj3560 pre mil 個數 zoj spa 應該

這個題不應該想不到的啊

考慮對於每個質因數分別計算答案,最後再乘起來

那麽每個答案就是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; }

bzoj3560: DZY Loves Math V