[题解]luogu_P4317_花神的数论题(数位dp

虽然是二进制但是和普通的数位dp没什么差别,统计1出现次数的乘积不如统计每个出现次数的数量,然后对应快速幂一下,转化成了平时熟悉的方案数,

状态设计:dfs里传什么参就开哪些状态,可以包括是否达到上限(lmt)之类的

#pragma GCC optimize(19260817)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=10000007;
ll n;
ll f[51][51][51][2],num[51];
ll qpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1)(ans*=a)%=mod;
        (a*=a)%=mod;
        b>>=1;
    }
    return ans%mod;
}
ll dfs(int x,int y,int lmt,int now){//x位y个1正统计now 
    if(x==0)return y==now;
    if(f[x][y][now][lmt]!=-1)return f[x][y][now][lmt];
    int top=lmt?num[x]:1;
    ll ans=0;
    for(int i=0;i<=top;i++)
    ans+=dfs(x-1,y+(i==1),lmt&&i==top,now);
    f[x][y][now][lmt]=ans;
    return ans;
}
ll g[51];
ll solve(){
    int len=0;
    while(n){
        num[++len]=n&1;
        n>>=1;
    }
    for(int i=1;i<=50;i++){
        memset(f,-1,sizeof(f));
        g[i]=dfs(len,0,1,i);
    }
    ll ans=1;
    for(int i=1;i<=50;i++)
    (ans*=qpow(i,g[i]))%=mod;
    return ans;
}
int main(){
    scanf("%lld",&n);
    printf("%lld\n",solve());
}

 

posted @ 2019-09-23 18:54  羊肉汤泡煎饼  阅读(137)  评论(0编辑  收藏  举报