zoukankan      html  css  js  c++  java
  • luogu_4317: 花神的数论题

    花神的数论题

    题意描述:
    • (sum(i))表示(i)的二进制数中(1)的个数。
    • 给定一个整数(N),求(prod_{i=1}^Nsum(i))
    输入描述:
    • 输入包含一个正整数(N(Nleq10^{15}))
    输出描述:
    • 一个数,答案模(10000007)的值。
    解题思路:
    • 数位(dp)+快速幂。
    • (f(i,j,k))表示以(k)开头的(i)位数中(1)的个数为(j)的数量。有转移方程
      • (f(i,j,0)=f(i-1,j,0)+f(i-1,j,1))
      • (f(i,j,1)=f(i-1,j-1,0)+f(i-1,j-1,1))
      • 这个很好理解,就是往最高位填(0/1)
    • (sum(i)==x)(i)(tot)个,那么他对答案的贡献显然就是(x^{tot})
    • 所以这时候枚举(x)就行,显然对于(N(Nleq 10^{15}))而言,不会枚举超过(60)次。
    • 详见代码:
    代码:
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 70, mod = 10000007;
    ll f[maxn][maxn][2];
    ll n, ans;
    
    inline ll qmi(ll a, ll b)
    {
        ll res = 1;
        while(b)
        {
            if(b & 1) res = (res * a) % mod;
            a = (a * a) % mod;
            b >>= 1ll;
        } return res % mod;
    }
    
    //x对应的二进制中有多少个1
    inline ll len(ll x)
    {
        ll res = 0;
        while(x)
        {
            if(x & 1ll) res++;
            x >>= 1ll;
        }
        return res;
    }
    
    int num[maxn], cnt;
    inline void work(ll x)
    {
        cnt = 0; ans = 1;
        while(x) //分解数位
        {
            num[++cnt] = x&1;
            x >>= 1;
        }
    
        //枚举m, 求出有多少i,有sum(i)=m
        for(int m = 1; m <= cnt; m++)
        {
            for(int i = 1; i < cnt; i++)
                ans = (ans * qmi(m, f[i][m][1]) % mod) % mod;
            //先枚举位数比n要小的数
            
            //开始处理位数和n相同的数字
            int k = m;
            //如果n的最高位是1的话
            //其实相当于把最高位固定了
            if(num[cnt]) k--;
            
            //从高位往低位枚举
            //之后我们让第i位小于n的第i位
            //这样可以让第i位后面的数字随便填写 
            for(int i = cnt - 1; i >= 1; i--)
            {
                for(int j = 0; j < num[i]; j++)
                    ans = (ans * qmi(m, f[i][k][j]) % mod) % mod;
                if(num[i]) k--; //相当于把第i位固定 因为i有1 所以k--
                if(k < 0) break;
            }
        }
        
        //由于一直卡上界,所以其实一直没有遇到等于n的情况
        //所以最后对n暴力分解数位处理一下
        ans = ((ans % mod) * (len(n) % mod)) % mod;
        printf("%lld
    ", ans);
    }
    
    inline void init()
    {
        scanf("%lld", &n);
        //dp预处理
        f[1][0][0] = f[1][1][1] = 1;
        for(int i = 1; i <= 60; i++)
        {
            for(int j = 0; j <= i; j++)
            {
                f[i+1][j+1][1] += f[i][j][0] + f[i][j][1];
                f[i+1][j][0] += f[i][j][0] + f[i][j][1];
            }
        } work(n);
    }
    
    int main()
    {
        init();
        return 0;
    }
    
    
  • 相关阅读:
    Nginx编译安装Lua模块
    Openresty =>nginx+lua
    windows下配置lua开发环境
    IntelljIdea安装nginx插件及单页面应用路由的nginx配置
    解决 start.spring.io 不能访问 使用阿里云国服链接替代
    Lua入门教程
    数据库锁机制] 深入理解乐观锁、悲观锁以及CAS乐观锁的实现机制原理分析
    前端MVC Vue2学习总结(一)——MVC与vue2概要、模板、数据绑定与综合示例
    Java死锁排查和Java CPU 100% 排查的步骤整理
    Windows平台安装配置Hadoop
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/11725517.html
Copyright © 2011-2022 走看看