Description

背景
众所周知,花神多年来凭借无边的神力狂虐各大 OJ、OI、CF、TC …… 当然也包括 CH 啦。
描述
话说花神这天又来讲课了。课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了。
花神的题目是这样的
设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,花神要问你
派(Sum(i)),也就是 sum(1)—sum(N) 的乘积。

Input

一个正整数 N。

Output

一个数,答案模 10000007 的值。

Sample Input

样例输入一
3

Sample Output

样例输出一

2

HINT

对于样例一,1*1*2=2;

数据范围与约定

对于 100% 的数据,N≤10^15


题目分析

是一道入门的数位dp(组合数)题。

但是这题结合了很多出题人的恶意,并且具有一定的启示作用。

 #include<bits/stdc++.h>
const int MO = ; int ans,pre;
int f[][];
int digit[];
long long n; int qmi(int a, int b)
{
int ret = ;
while (b)
{
if (b&) ret = 1ll*ret*a%MO;
a = 1ll*a*a%MO;
b >>= ;
}
return ret;
}
int main()
{
scanf("%lld",&n);
f[][] = , ans = ;
for (n++; n; n>>=) digit[++digit[]] = n&;
for (int i=; i<=digit[]; i++)
{
f[i][] = ;
for (int j=; j<=i; j++)
f[i][j] = f[i-][j]+f[i-][j-];    //预处理组合数
}
for (int i=digit[]; i; i--)
if (digit[i]){
for (int j=i-; j>=; j--)
ans = 1ll*ans*qmi(pre+j, f[i-][j])%MO;
pre++;
}
printf("%d\n",ans);
return ;
}

最初会自然地想到上面这种dp方法。

但是!这里的细节显然崩坏了。

二进制拆分

 int digit[];

二进制拆分时候$digit[]$干嘛开这么小啊……注意要大概开个三倍。

组合数取模

     for (int i=; i<=digit[]; i++)
{
f[i][] = ;
for (int j=; j<=i; j++)
f[i][j] = f[i-][j]+f[i-][j-];
}

这里组合数不取模显然是会溢出的。但是,重点是取什么模呢?可能会不假思索地%1e7+7,然而实际上1e7+7并不是一个素数,所以这里要回到欧拉定理,我们有$φ(1e7+7)=9988440$。再者就是注意这里只有组合数需要对$φ(1e7+7)$取模。

溢出会RE;或是莫名其妙TLE。

dp的转移

     for (int i=digit[]; i; i--)
if (digit[i]){
for (int j=i-; j>=; j--)
ans = 1ll*ans*qmi(pre+j, f[i-][j])%MO;
pre++;
}

注意到这里内层的$j>=1$,但是由于后面的元素可以不选,事实上$j$应该$>=0$才对。

手调时候会发现当$j=0,pre=0$时,$ans$就等于0了。

所以还要在快速幂里特判一层: if (!a) return ; 。

正确代码

 #include<bits/stdc++.h>
const int MO = ; int ans,pre;
int f[][];
int digit[];
long long n; int qmi(int a, int b)
{
if (!a) return ;
int ret = ;
while (b)
{
if (b&) ret = 1ll*ret*a%MO;
a = 1ll*a*a%MO;
b >>= ;
}
return ret;
}
int main()
{
scanf("%lld",&n);
f[][] = , ans = ;
for (n++; n; n>>=) digit[++digit[]] = n&;
for (int i=; i<=digit[]; i++)
{
f[i][] = ;
for (int j=; j<=i; j++)
f[i][j] = (f[i-][j]+f[i-][j-])%;
}
for (int i=digit[]; i; i--)
if (digit[i]){
for (int j=i-; j>=; j--)
ans = 1ll*ans*qmi(pre+j, f[i-][j])%MO;
pre++;
}
printf("%d\n",ans);
return ;
}

END

【数位dp】bzoj3209: 花神的数论题的更多相关文章

  1. BZOJ3209 花神的数论题 【组合数学+数位DP+快速幂】*

    BZOJ3209 花神的数论题 Description 背景 众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦. 描述 话说花神这天又来讲课了.课后照例有 ...

  2. [bzoj3209]花神的数论题_数位dp

    花神的数论题 bzoj-3209 题目大意:sum(i)表示i的二进制表示中1的个数,求$\prod\limits_{i=1}^n sum(i)$ 注释:$1\le n\le 10^{15}$. 想法 ...

  3. [Bzoj3209]花神的数论题(数位dp)

    3209: 花神的数论题 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2633  Solved: 1182[Submit][Status][Disc ...

  4. BZOJ3209: 花神的数论题(数位DP)

    题目: 3209: 花神的数论题 解析: 二进制的数位DP 因为\([1,n]\)中每一个数对应的二进制数是唯一的,我们枚举\(1\)的个数\(k\),计算有多少个数的二进制中有\(k\)个\(1\) ...

  5. [BZOJ3209]花神的数论题 组合数+快速幂

    3209: 花神的数论题 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2498  Solved: 1129[Submit][Status][Disc ...

  6. bzoj3209 花神的数论题——数位dp

    题目大意: 花神的题目是这样的 设 sum(i) 表示 i 的二进制表示中 1 的个数.给出一个正整数 N ,花神要问你 派(Sum(i)),也就是 sum(1)—sum(N) 的乘积. 要对1000 ...

  7. [bzoj3209][花神的数论题] (数位dp+费马小定理)

    Description 背景众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦.描述话说花神这天又来讲课了.课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了. ...

  8. bzoj3209 花神的数论题 (二进制数位dp)

    二进制数位dp,就是把原本的数字转化成二进制而以,原来是10进制,现在是二进制来做,没有想像的那么难 不知到自己怎么相出来的...感觉,如果没有一个明确的思路,就算做出来了,也并不能锻炼自己的能力,因 ...

  9. BZOJ3209 花神的数论题

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

随机推荐

  1. sql server随机排序和随机取出n条数据

    问题:博主在2010-2011学年,广东技术师范大学大四的时候,去过红海人力集团面试数据库职位,很清楚记得当时有一道笔试题目是:编写sql从表里面随机取出10条记录. 解决方案:在sql server ...

  2. assembly x86(nasm)画三角形等图形的实现(升级版)

    https://www.cnblogs.com/lanclot-/p/10962702.html接上一篇 本来就有放弃的想法,可是有不愿退而求次, 然后大神室友写了一个集海伦公式计算三角形面积, 三点 ...

  3. 关于 js中的arguments 对象

    arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推.这个对象只有在函数体内部,才可以使用. var f = fu ...

  4. 字符条件变成in条件格式数据

    private string getInQuerySql(string query) { string resulr = ""; foreach (var item in quer ...

  5. 未知宽高div水平垂直居中的3种方法

    方法一 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...

  6. 旧版本linaro-ubuntu更改软件源

    最近打算研究下arm版本的linaro ubuntu桌面系统,但是在安装软件时速度实在太慢,便想修改一下软件源. 无奈查看系统版本时,显示的是linaro 11.12,但却不知和ubuntu有和关系, ...

  7. Qt 2D绘图之四:绘图中的其他问题

    一.重绘事件 前面讲到的所有绘制操作都是在重绘事件处理函数paintEvent()中完成的,是QWidget类中定义的函数.一个重绘事件用来重绘一个部件的全部或者部分区域,下面几个原因中的任意一个都会 ...

  8. python入门之冒泡排序

    原理: (白话描述)一列数,从左到右,依次两两比较,若左边的数大于右边的数,则两数交换,始终保持比较后左边的数小于右边的数,这样从第一个到最后一个数全部比较一次就会把这列数中的最大值排到最后(最右边) ...

  9. 神奇的VIM

    1. di'.di".di`.di( .di{ .dt 'abc' ==> '' di' "abc"==> "" di" `ab ...

  10. kafka基础二

    kafka生产者工作流程 消息产生分析 1.写入方式: producer采用推(push)模式将消息发布到broker,每条消息都会被追加(append)到分区Partition上,属于顺序写磁盘(顺 ...