Project Euler #650

水幾個簡單PE題解,難的留着以後出(ban)。。。

傳送門ber~

題意:求S(n)=k=1nD(k)S(n)=\sum_{k=1}^{n}D(k),D(n)=dB(n)dD(n)=\sum_{d|B(n)}d,B(n)=k=0nC(n,k)B(n)=\prod_{k=0}^{n}C(n,k)

這題就看着嚇人點,,,瞎jb化化就沒了…

B(n)B(n)中所有的組合數拆開,即
B(n)=k=0nC(n,k)=k=0nn!k!(nk)!=(n!)n+1(1n2n13n2...n)2=1n+12n+1...nn+1(1n2n13n2...n)2=k=1nk2kn1 \begin{aligned} B(n) &= \prod_{k=0}^{n} C(n,k) \\ &=\prod_{k=0}^{n} \frac{n!}{k!(n-k)!}\\ &=\frac{(n!)^{n+1}}{(1^{n}*2^{n-1}*3^{n-2}*...*n)^2}\\ &=\frac{1^{n+1}*2^{n+1}*...*n^{n+1}}{(1^{n}*2^{n-1}*3^{n-2}*...*n)^2}\\ &=\prod_{k=1}^n k^{2k-n-1} \end{aligned}
對於B(n)B(n)可以在O(n1.5)O(n^{1.5})的複雜度唯一分解
容(shu)易(xue)發(chang)現(shi)D(x)D(x)是個積性函數
那麼求出每個D(piai)D(p_i^{a_i})乘一塊就完了,並且D(piai)=j=1aipij=piai+1pi1D(p_i^{a_i})=\sum_{j=1}^{a_i} p_i^{j}=\frac{p_i^{a_i}+1}{p_i-1},可以直接求出
然後SS裏面直接枚舉就夠了。。。總複雜度大概O(n2logn)O(n^2*logn)?反正二十多秒跑出來了

代碼如下:

#include<bits/stdc++.h>
#define N 5000020
using namespace std;
const int MOD=1e9+7;
typedef long long LL;
int n,top;
int prime[N],f[N][30];
LL val[N],tmp,ans;
bool pd[N];
inline void prime_shaker(int n){
    for(int i=2;i<=n;i++){
        if(!pd[i]) prime[++top]=i;
        for(int j=1;j<=top && 1ll*i*prime[j]<=n;j++){
            pd[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}
inline void divide(int x,int k){
    for(int i=1;i<=top && 1ll*prime[i]*prime[i]<=x;i++)
        while(x%prime[i]==0){
            val[i]+=k;
            x=x/prime[i];
        }
    if(x!=1){
        int t=lower_bound(prime+1,prime+top+1,x)-prime;
        val[t]+=k;
    }
}
inline int qpow(int x,int k){
    int sum=1;
    while(k){
        if(k&1) sum=1ll*sum*x%MOD;
        x=1ll*x*x%MOD;
        k>>=1;
    }
    return sum;
}
int main(){
    scanf("%d",&n);prime_shaker(n);
    for(int i=1;i<=top;i++)
        for(int j=f[i][0]=1;j<=20;j++)
            f[i][j]=(f[i][j-1]+qpow(prime[i],j))%MOD;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=top;j++) val[j]=0;
        for(int j=2;j<=i;j++) divide(j,2*j-i-1);
        tmp=1;
        for(int j=1;j<=top;j++){
            LL t=1ll*(qpow(prime[j],val[j]+1)+MOD-1)*qpow(prime[j]-1,MOD-2)%MOD;
            ///for(int l=1;l<=val[j];l++) t=(t+qpow(prime[j],l))%MOD;
            tmp=(1ll*tmp*t)%MOD;
        }
        ans=(ans+tmp)%MOD;
    }
    printf("%lld\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章