zoukankan      html  css  js  c++  java
  • Luogu P4317 花神的数论题

    也是一道不错的数位DP,考虑先转成二进制后再做

    转化一下问题,考虑统计出([1,n])中在二进制下有(i)(1)的方案数(cnt_i),那么答案显然就是(prod i^{cnt_i})

    然后我们还是先预处理一个东西(s_{i,j}),表示在二进制下前(i)位中填上(j)(1)的方案数,则有转移:

    (s_{i,j}=s_{i-1,j}+s_{i-1,j-1}(i>1)),同时有(s_{i,0}=1)

    这转移很简单吧,就是考虑这一位填上(0/1)

    观察一下发现其实这就是个杨辉三角,不过好像并没有什么用。

    接下来枚举有(i)(1)的情况,那么从高位填到低位,对于每一位上的(1),我后面怎么填都是满足要求的

    因此此时的(cnt_i+=s_{l,k})(l)表示后面还有多少位(比它低的位),(k)表示之前(包括现在)已经出现多少个(1),最后直接快速幂计算一下就好了。

    注意到这样只能处理小于(n)的数的情况(一般很多二进制下的数位DP都有这个通病),所以我们直接把(n)加一即可。

    CODE

    #include<cstdio>
    using namespace std;
    const long long N=65,mod=10000007;
    long long n,s[N][N],ans=1LL,cnt,bit[N];
    inline void resolve(long long x)
    {
        while (x) bit[++cnt]=x&1,x>>=1;
    }
    inline long long solve(long long x)
    {
        register long long i; long long tot=0;
        for (i=cnt;i>=1&&~x;--i)
        if (bit[i]) tot+=s[i-1][x--];
        return tot;
    }
    inline long long quick_pow(long long x,long long p)
    {
        long long tot=1;
        while (p)
        {
            if (p&1) tot=tot*x%mod;
            x=x*x%mod; p>>=1;
        }
        return tot;
    }
    int main()
    {
        register long long i,j; scanf("%lld",&n); resolve(++n);
        for (s[0][0]=1,i=1;i<=cnt;++i)
        for (j=0;j<=i;++j)
        s[i][j]=j?s[i-1][j]+s[i-1][j-1]:s[i-1][j];
        for (i=1;i<=cnt;++i)
        ans=ans*quick_pow(i,solve(i))%mod;
        return printf("%lld",ans),0;
    }
    
  • 相关阅读:
    Atitit.atiRI  与 远程调用的理论and 设计
    Atitit.提升 升级类库框架后的api代码兼容性设计指南
    Atitit.研发管理软件公司的软资产列表指南
    Atitit.软件开发的三层结构isv金字塔模型
    Atitit.加密算法ati Aes的框架设计
    Atittit.研发公司的组织架构与部门架构总结
    IIS HTTP Error 500.24
    Visual Studio 快捷键
    软件学习遐想
    navigator属性
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9478416.html
Copyright © 2011-2022 走看看