#95 qsc oj 喵哈哈村的秘境探险(四)(数位dp, 组合数,快速幂)

题目链接:http://www.qscoj.cn/problem/95/


喵哈哈村的秘境探险(四)

发布时间: 2017年4月25日 20:24   最后更新: 2017年4月25日 20:25   时间限制: 1000ms   内存限制: 128M

喵哈哈村的一堆人在前往北京的路上,发现了一个洞穴。由于好奇心大作,于是准备前往洞穴进行探险。

走啊走,喵哈哈村一群人发现了一个先知,这个先知想知道:

设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,先知要问你,sum(1)到sum(n)的乘积是多少。

一个正整数 N。

N<=1e15

一个数,答案模 10000007 的值。

  复制
8
24
   


解析:求的是1~n中每个数含1个数的乘积,思路就是合理运用组合数,预先处理好i位选j个1的组合数组c[i][j],然后就是输入一个n,先把它转换成二进制,对于二进制中每一位上的1,咱可以把1后面的所有组合算一下,然后ans再乘以包含此位1的个数,比如说n的二进制为 10000101,计算第一个1,也就是计算1~10000000,然后就是计算10000000~10000100,再然后就是计算10000100~10000101,这样就不会漏掉某个数,ans初始化为1,累乘即可

代码:

#include<bits/stdc++.h>
#define N 109
using namespace std;
typedef long long LL;
const LL mod = 10000007ll;

LL c[69][69];

void init()
{
    c[0][0] = c[1][1] = c[1][0] = 1ll;
    for(int i = 1; i <= 63; i++)
    {
        for(int j = 1; j < i; j++)
            c[i][j] = c[i-1][j] + c[i-1][j-1];
        c[i][0] = c[i][i] = 1;
    }
}

LL Pow(LL a, LL b)
{
    LL ans = 1ll;
    while(b)
    {
        if(b&1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans % mod;
}


LL bits[69];

LL solve(LL n)
{
    int len = 1;
    while(n)
    {
        if(n&1) bits[len++] = 1;
        else bits[len++] = 0;
        n >>= 1;
    }
    // len
    LL ans = 1ll; len--;
    for(int i = 2; i < len; i++)
    {
        ans = (ans * Pow(i, c[len-1][i])) % mod;
    }
    LL k = 1ll;
    for(int i = len - 1; i >= 1; i--)
    {
        if(bits[i])
        {
            for(int j = 1; j < i; j++)
                ans = (ans * Pow(j + k, c[i - 1][j])) % mod;
            k++;
            ans = ans * k % mod;
        }
    }
    return ans % mod;

}


int main()
{
    init();
    LL n;
    scanf("%lld", &n);
    cout << solve(n) << endl;
    return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值