DP,數論————洛谷P4317 花神的數論題(求1~n二進制中1的個數和)

玄學代碼(是洛谷題解裏的一位dalao小粉兔寫的)ios

//數位DP(二進制)計算出f[i]爲剛好有i個的方案數。
//答案爲∏(i^f[i]),快速冪解決。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=10000007;
ll n,ans=1;
ll c,f[50];
ll qpow(ll b,ll e){
    ll a=1;
    for(;e;b=b*b%mod,e>>=1)
        e&1?a=a*b%mod:0;
    return a;
}

int main(){
    scanf("%lld",&n);
    for(int j=49;~j;--j){
        for(int i=49;i;--i)
            f[i]+=f[i-1];
        if(n>>j&1)++f[c++];
    }++f[c];
    for(int i=1;i<=49;++i)
        ans=ans*qpow(i,f[i])%mod;
    printf("%lld",ans);
    return 0;
}

下面是另外一位dalaoStyx寫的簡單易懂的題解c++

代碼以下ui

#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mod 10000007
using namespace std;

long long ans=1,n,k,cnt,dp[110][110];

long long kasumi(long long a,long long b)
{
    long long tmp=1;
    while(b)
    {
        if(b&1) tmp=(tmp%mod)*a%mod;
        a=(a%mod)*a%mod;
        b>>=1;
    }
    return tmp%mod;
}

int main()
{
    scanf("%lld",&n);
    for(int i=1; i<=60; i++)
    {
        dp[i][1]=1;
    }
    for(int i=1; i<=60; i++)
    {
        dp[i][i]=1;
    }
    for(int i=2; i<=60; i++)
    {
        for(int j=2; j<i; j++)
        {
            dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
        }
    }
    for(k=1; k<=n; k<<=1)
    {
        n-=k;
        cnt++;
        for(int j=1; j<=cnt; j++)
        {
            ans=(ans%mod)*kasumi(j,dp[cnt][j])%mod;
            ans%=mod;
        }
    }
    cnt=0;
    for(int i=60;i>=0;i--)
    {
        if((1ll<<i)<=n)
        {
            for(int j=1;j<=i+1;j++)
            {
                ans=(ans%mod)*kasumi(j+cnt,dp[i+1][j]);
                ans%=mod;
            }
            cnt++;
            n-=(1ll<<i);
        }
    }
    printf("%lld\n",ans);
}

至於爲何不用擴展歐拉定理降冪,那是由於楊輝三角在總和等於1e15的時候 ,每個數確定不會爆longlongspa

相關文章
相關標籤/搜索