zoukankan      html  css  js  c++  java
  • bzoj 3209 花神的数论题——二进制下的数位dp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3209

    可以枚举 “1的个数是...的数有多少个” ,然后就是用组合数算在多少位里选几个1。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int mod=1e7+7,N=70;//(1e7+7)%941==0
    ll n,dg[N];
    int jc[N],jcn[N],cnt,ans=1;
    int pw(int x,int k)
    {
        int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret;
    }
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    void exgcd(int a,int b,int &x,int &y)
    {
        if(!b){x=1;y=0;return;}
        exgcd(b,a%b,y,x);y-=a/b*x;
    }
    void init()
    {
        jc[0]=1;
        for(int i=1;i<=62;i++)jc[i]=(ll)jc[i-1]*i%mod;
        int y;exgcd(jc[62],mod,jcn[62],y);
        for(int i=61;i>=0;i--)jcn[i]=(ll)jcn[i+1]*(i+1)%mod;
    }
    int C(int n,int m)
    {
        if(m>n)return 0;if(!m)return 1;
        return (ll)jc[n]*jcn[m]%mod*jcn[n-m]%mod;
    }
    int main()
    {
        init();
        scanf("%lld",&n);
        ll m=n;int p0=0;
        while(m)
        {
            ll k=(m&-m);
            for(;(1ll<<p0)!=k;p0++);
            dg[++cnt]=p0;m-=(m&-m);
        }
        for(int i=1;i<=dg[cnt]+1;i++)
            for(int j=cnt,k=0;j>=0&&k<=i;j--,k++)
                ans=(ll)ans*pw(i,C(dg[j],i-k))%mod;//模数不是质数,不能对指数取模!!! 
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    模数有毒吧怎么不是质数啊!这样都没法对指数取模了!

    然后得知是数位dp。同样是枚举 “1的个数是...的数有多少个” ,但因为不是组合数,所以long long就行啦!

    dp[ i ][ j ]表示第 i 位是0,后面从0..00到1..11中有多少个数有 j 个1。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=62,mod=1e7+7;
    ll n,dp[N+5][N+5];
    int m,dg[N+5],cnt,ans=1;
    void init()
    {
        dp[1][0]=1;
        for(int i=2;i<=m;i++)
            for(int j=0;j<=i;j++)
                dp[i][j]+=dp[i-1][j]+dp[i-1][j-1];
    }
    int pw(int x,ll k)
    {
        if(!x)return 1;
        int ret=1;while(k){if(k&1ll)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1ll;}return ret;
    }
    int main()
    {
        scanf("%lld",&n);
        for(m=0;m<=N&&(1ll<<m)<=n;m++);
        init();
        ll c=n;int p0=0;
        while(c)
        {
            ll k=(c&-c);
            for(;(1ll<<p0)!=k;p0++);
            dg[++cnt]=p0+1;c-=k;
        }
        for(int i=cnt,k=0;i>=0;i--,k++)
        {
            if(!i){ans=(ll)ans*k%mod;break;}
            for(int j=0;j<=dg[i]-1;j++)
                ans=(ll)ans*pw(j+k,dp[dg[i]][j])%mod;
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    从零开始学Kotlin-使用接口(7)
    从零开始学Kotlin-类的继承(6)
    从零开始学Kotlin-类和对象(5)
    从零开始学Kotlin-控制语句(4)
    从零开始学Kotlin-操作符(3)
    从零开始学Kotlin-数据类型(2)
    从零开始学Kotlin-基础语法(1)
    Java设计模式之单例模式(七种写法)
    一个简单的可控的头像列表叠加控件
    使用NestedScrollView+ViewPager+RecyclerView+SmartRefreshLayout打造酷炫下拉视差效果并解决各种滑动冲突
  • 原文地址:https://www.cnblogs.com/Narh/p/9399591.html
Copyright © 2011-2022 走看看