定義f[n]表示n是最大公約數情況下的計數,F[n]為n是公約數情況下的計數
(可以和 http://www.cnblogs.com/Just--Do--It/p/7197788.html hdu1695 進行類比)
顯然F[n]和f[n]是滿足下面這個關系的
所以,可以用下面這個公式求解f[n]
得到下面的AC代碼
#include<bits/stdc++.h> using namespace std; typedef long long LL; #define max(a,b) ((a)>(b)? (a):(b)) #define min(a,b) ((a)<(b)? (a):(b)) const int maxn=1e5+7; int prime[maxn+5]; bool check[maxn+5]; int mu[maxn+5]; void init() { mu[1]=1; int tot=0; for(int i=2;i<=maxn;i++) { if(!check[i]) { prime[tot++]=i; mu[i]=-1; } for(int j=0;j<tot;j++) { if(i*prime[j]>maxn) break; check[i*prime[j]]=true; if(i%prime[j]==0) { mu[i*prime[j]]=0; break; } else { mu[i*prime[j]]=-mu[i]; } } } } const int N=1e5+5; const int mod=1e9+7; int n; int num[2*N]; LL F[N]; LL f[N]; LL qpow(LL x,LL n) { LL ret=1; for(;n;n>>=1) { if(n&1) ret=ret*x%mod; x=x*x%mod; } return ret; } int main() { init(); int T; scanf("%d",&T); for(int kase=1;kase<=T;kase++) { memset(num,0,sizeof(num)); memset(f,0,sizeof(f)); int max_gcd=1e9,max_a=0; LL ans=0; scanf("%d",&n); for(int i=0;i<n;i++) { int t; scanf("%d",&t); num[t]++; max_gcd=min(t,max_gcd); max_a =max(t,max_a ); } for(int i=1;i<2*N;i++) num[i]+=num[i-1]; for(int i=2;i<=max_gcd;i++) { F[i]=1; for(int j=i;j<=max_a;j+=i) F[i]=F[i]*qpow(j/i,num[j+i-1]-num[j-1])%mod; } // ================================= for(int i=2;i<=max_gcd;i++) for(int j=1;i*j<=max_gcd;j++) f[i]=(f[i]+mu[j]*F[i*j])%mod; for(int i=2;i<=max_gcd;i++) ans=(ans+f[i])%mod; // ================================= printf("Case #%d: %lld\n",kase,ans); } }
然而!=====所夾的部分可以用一行代碼代替!!!!雖然運行時間不會減少多少,不過代碼量上優化了很多!
不過這種寫法的實質其實可以從容斥原理的角度來考慮,再借用了莫比烏斯函數的性質。
定義: 性質Pi表示i是對象x的一個質因數, 集合Ai表示具有性質Pi的對象的集合
比較容易想到,所有可能的公因數對應的對象計數之和,恰為所有集合的並 中的對象的總個數
那么用容斥原理求 所有集合的並 中的對象的總個數時,奇數個基本集合的交前面的系數是正一,偶數個的是負一。並且,n的因數中包含質因數平方的F[n]在這里面是不需要被計數的。
這樣恰好就與莫比烏斯函數的性質產生了聯系。
參考博客: http://blog.csdn.net/acterminate/article/details/76216345
也就變成了
#include<bits/stdc++.h> using namespace std; typedef long long LL; #define max(a,b) ((a)>(b)? (a):(b)) #define min(a,b) ((a)<(b)? (a):(b)) const int maxn=1e5+7; int prime[maxn+5]; bool check[maxn+5]; int mu[maxn+5]; void init() { mu[1]=1; int tot=0; for(int i=2;i<=maxn;i++) { if(!check[i]) { prime[tot++]=i; mu[i]=-1; } for(int j=0;j<tot;j++) { if(i*prime[j]>maxn) break; check[i*prime[j]]=true; if(i%prime[j]==0) { mu[i*prime[j]]=0; break; } else { mu[i*prime[j]]=-mu[i]; } } } } const int N=1e5+5; const int mod=1e9+7; int n; int num[2*N]; LL F[N]; LL f[N]; LL qpow(LL x,LL n) { LL ret=1; for(;n;n>>=1) { if(n&1) ret=ret*x%mod; x=x*x%mod; } return ret; } int main() { init(); int T; scanf("%d",&T); for(int kase=1;kase<=T;kase++) { memset(num,0,sizeof(num)); memset(f,0,sizeof(f)); int max_gcd=1e9,max_a=0; LL ans=0; scanf("%d",&n); for(int i=0;i<n;i++) { int t; scanf("%d",&t); num[t]++; max_gcd=min(t,max_gcd); max_a =max(t,max_a ); } for(int i=1;i<2*N;i++) num[i]+=num[i-1]; for(int i=2;i<=max_gcd;i++) { F[i]=1; for(int j=i;j<=max_a;j+=i) F[i]=F[i]*qpow(j/i,num[j+i-1]-num[j-1])%mod; // printf("F[%d]=%4lld\n",i,F[i]); ans=(ans-mu[i]*F[i]+mod)%mod; } printf("Case #%d: %lld\n",kase,ans); } }