Live2D

BZOJ3209: 花神的数论题

重在建模QwQ,要将题意转化为

枚举1的个数k,计算有多少个数含有k个1,(因为数位dp就是来做,有多少满足的数,且不关注数的大小)

最后加个快速幂就好

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

typedef long long ll;
ll ans[70],n,dp[70][70][70];
ll num[70];
const ll mod=10000007;

inline ll dfs(int pos,int now,int goal,bool limit)
{
    if(pos==0&&now==goal) return 1;
    if(pos==0) return 0;
    if(!limit&&dp[pos][now][goal]!=-1) return dp[pos][now][goal];
    int up=1; ll tot=0;
    if(limit) up=num[pos];
    for(register int i=0;i<=up;++i)
    {
        if(i==1) tot+=dfs(pos-1,now+1,goal,limit&&(i==num[pos]));
        else tot+=dfs(pos-1,now,goal,limit&&(i==num[pos]));
    } 
    if(!limit) dp[pos][now][goal]=tot;
    return tot;
}

inline ll quick_pow(ll x,ll y)
{
    if(y==0) return 1;
    if(y==1) return x%mod;
    if(y%2==0)
    {
        ll tmp=quick_pow(x,y/2)%mod;
        return tmp*tmp%mod;
    }
    if(y%2!=0)
    {
        ll tmp=quick_pow(x,y/2)%mod;
        return x%mod*tmp*tmp%mod;
    } 
}

inline ll solve(ll k)
{
    int pos=0;
    while(k>0)
    {
        num[++pos]=k&1;
        k=k>>1;
    }
    for(register int i=1;i<=60;++i)
        ans[i]=dfs(pos,0,i,true);
    ll res=1;
    for(register int i=2;i<=60;++i)
        res=(res*quick_pow(i,ans[i]))%mod;
    return res;
}

int main()
{
    scanf("%lld",&n);
    memset(dp,-1,sizeof(dp));
    printf("%lld\n",solve(n));
    return 0;
}

 

 

 

 

 

posted @ 2019-11-12 11:24  Hoyoak  阅读(128)  评论(0编辑  收藏  举报