1. 程式人生 > >bzoj 3209: 花神的數論題【數位dp】

bzoj 3209: 花神的數論題【數位dp】

clas tail code 花神的數論題 turn a* names blog nsh

參考:https://blog.csdn.net/sunshinezff/article/details/51049132
非典型數位dp
首先預處理,設f[i][j]為以0開頭的i位數中1的個數為j的數的數量,g[i][j]為以1開頭的i位數中1的個數為j的數的數量;轉移是 f[i][j]=f[i-1][j]+g[i-1][j],g[i][j]=f[i-1][j-1]+g[i-1][j-1]
然後做數位dp,對於n在二進制下為1的位統計這樣的1的個數出現過幾次,然後快速冪即可

#include<iostream>
#include<cstdio>
using namespace std;
const int N=65,mod=10000007;
long long n,f[N][N],g[N][N];
long long ksm(long long a,long long b)
{
    long long r=1ll;
    while(b)
    {
        if(b&1)
            r=r*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return r;
}
int main()
{
    scanf("%lld",&n);
    f[1][0]=1,g[1][1]=1;
    for(int i=2;i<=60;i++)
        for(int j=0;j<=i;j++)
        {
            f[i][j]=f[i-1][j]+g[i-1][j];
            if(j>0)
                g[i][j]=f[i-1][j-1]+g[i-1][j-1];
        }
    long long t=0,c=0,ans=1;
    for(t=0;(1ll<<t)<=n;t++);
    for(;t;t--)
        if(1ll<<(t-1)&n)
        {
            for(int i=1;i<=t;i++)
                ans=ans*ksm(i+c,f[t][i])%mod;
            if(c)
                ans=ans*c%mod;
            c++;
        }
    printf("%lld\n",ans*c%mod);
    return 0;
}

bzoj 3209: 花神的數論題【數位dp】