• 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;
    }
    
  • 相关阅读:
    提高效率
    kill 挂起 Apache Web Server
    /var/spool/mail/root
    https://github.com/PyMySQL/PyMySQL/blob/master/pymysql/connections.py
    top swap
    top load average
    Difference between exit() and sys.exit() in Python
    八进制权限掩码 3位 4位 setuid setgid sticky
    以二进制和八进制方式表示文件模式
    0 lrwxrwxrwx. 1 root root 13 Nov 20 12:44 scala -> scala-2.12.4
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9478416.html
Copyright © 2020-2023  润新知