bzoj3209 花神的数论题 数位DP

来源:互联网 发布:网络暴力调查报告配图 编辑:程序博客网 时间:2024/05/22 15:38

一开始想的是先预处理出n位的答案,因为假设当前给出的数x有y位,那么y-1位的答案是固定的,我只要处理y位的答案就可以了,问题是这样太复杂。。。
设f[i][j]表示i位有j个1的答案,那么明显有f[i][j]=f[i-1][j]+f[i-1][j-1],表示第i位选0或1.
然后最后统计一下答案,就是每一种出现了多少次。。

其实挺简单的,基本想出来了,但是数位dp不熟,想的复杂了。

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=1e5+5;const int mo=10000007;typedef long long ll;ll n;ll sum[100],f[100][100],g[100];int wei[N];int tot;ll ans;inline void pre(){    f[0][0]=1;    fo(i,1,60)    {        f[i][0]=1;        fo(j,1,i)        f[i][j]=f[i-1][j-1]+f[i-1][j];    }}ll solve(int x){    ll sum=0;    fd(i,tot,1)    {        if (wei[i]==1)        {            sum+=f[i-1][x];            --x;        }        if (x<0)break;    }    return sum;} ll pow(ll a,ll b){    ll ret=1;    while (b)    {        if (b&1)ret=ret*a%mo;        a=a*a%mo;        b>>=1;    }    return ret;}int main(){    pre();    scanf("%lld",&n);    ++n;    tot=0;    while (n)    {        wei[++tot]=n&1;        n>>=1;    }    ans=1ll;    fo(i,1,tot)    ans=ans*pow(i,solve(i))%mo;    printf("%lld\n",ans%mo);    return 0;}
原创粉丝点击