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;
    }
  • 相关阅读:
    计算位数
    素数的判断(大数据,大规模)
    Patting Heads
    Jury Jeopardy (这是一道单纯的模拟题)
    POJ 2229 Sumsets(规律)
    OJ 26217 :Work Scheduling(贪心+优先队列)
    牛客Professional Manager(并查集)
    DJ 算法的队列优先优化
    优先队列priority_queue的简单应用
    node.js服务端存储用户密码md5加密
  • 原文地址:https://www.cnblogs.com/Narh/p/9399591.html
Copyright © 2011-2022 走看看