题目描述

为了揭穿$SERN$的阴谋,$Itaru$黑进了$SERN$的网络系统。
然而,想要完全控制$SERN$,还需要知道管理员密码。$Itaru$从截获的信息中发现,$SERN$的管理员密码是两个整数$l,s,0\leqslant s\leqslant l$,并且一旦得知了管理员密码,就可以生成出$SERN$各个网路接口的密码:各个网络接口的密码均是若干个长为$l$的$0/1$串,且每个串中$1$的个数恰为$s$。不难发现,生成的密码串个数是一个组合数。
$SERN$的网络系统是由$p^k$个网络接口构成的,$SERN$为了保证网络系统的稳定性,保证了$p$为质数,且所有生成的密码串个数能被$p^k$整除。为了网络通讯的方便,$SERN$的网络接口的密码不会太长,即可以保证$l\leqslant N$。
作为一名$Super\ Hacker$,$Itaru$已经想到了破解密码的绝妙方法,然而在这之前,他需要确认管理员密码的可能情况有多少。由于答案可能很大,答案对${10}^9+7$取模。


输入格式

仅包含一行三个整数$N,p,k$。


输出格式

仅包含一个整数,表示答案。


样例

样例输入:

4 2 2

样例输出:

2


数据范围与提示

样例解释:

有$2$种可能的情况,$l=4,s=1;l=4s=3$。

数据范围:

保证$1\leqslant p,k\leqslant {10}^9,1\leqslant N\leqslant {10}^{1000}$,$p$为质数。
各个测试点还满足如下约束:


题解

又是数学题,那就化式子。

组合数与阶乘有关,我们可以先考虑阶乘。
对于$n!$,满足$p^k|n!$的最大的$k$为:$$maxk=\sum \limits_{i=1}^{\infty}\left \lfloor \frac{n}{p^i}\right \rfloor$$
那么对于$C_n^m$,由于$C_n^m=\frac{n!}{m!(n-m)!}$,满足$p^k|C_n^m$的最大的$k$为:$$maxk=\sum \limits_{i=1}^{\infty}\left \lfloor \frac{n}{p^i}\right \rfloor-\left \lfloor \frac{m}{p^i}\right \rfloor-\left \lfloor \frac{n-m}{p^i}\right \rfloor \left \lfloor \frac{n-m}{p^i}\right \rfloor$$

然后我们引入一个新的名词:库默尔定理。

那么,什么是库默尔定理呢?

设$m,n$为正整数,$p$为素数,则$C_{m+n}^m$含$p$的幂次等于$m+n$在$p$进制下的进位次数。

下面给出证明:

组合数$C_{n+m}^m$所含$p$的幂次数为:$$\sum \limits_{i=1}^{\infty}\left \lfloor \frac{m+n}{p^i}\right \rfloor-\sum \limits_{i=1}^{\infty}\left \lfloor \frac{n}{p^i}\right \rfloor-\sum \limits_{i=1}^{\infty}\left \lfloor \frac{m}{p^i}\right \rfloor \\ =\sum \limits_{i=1}^{\infty}(\left \lfloor \frac{m+n}{p^i}\right \rfloor-\left \lfloor \frac{n}{p^i}\right \rfloor-\left \lfloor \frac{m}{p^i}\right \rfloor)$$

这是因为组合数公式$C_{n+m}^n=\frac{(n+m)!}{n!m!}$以及$n!$含有素数$p$的幂次公式$vp(n!)=\sum \limits_{i=1}^{\infty} \left \lfloor \dfrac{n}{p^i}\right \rfloor$。

对于某个$p^i$,$\left \lfloor \frac{m}{p^i}\right \rfloor$等于$m$在$p$进制表示下去掉后$i$位,在第$i+1$位上,$n+m$在这一位上进位的充要条件是$$\left \lfloor \frac{n+m}{p^i}\right \rfloor-\left \lfloor \frac{n}{p^i}\right \rfloor-\left \lfloor \frac{m}{p^i}\right \rfloor=1$$不进位则$$\left \lfloor \frac{n+m}{p^i}\right \rfloor-\left \lfloor \frac{n}{p^i}\right \rfloor-\left \lfloor \frac{m}{p^i}\right \rfloor=0$$因此$\sum \limits_{i=1}^{\infty}(\left \lfloor \frac{m+n}{p^i}\right \rfloor-\left \lfloor \frac{n}{p^i}\right \rfloor-\left \lfloor \frac{m}{p^i}\right \rfloor)$就是$n+m$在$p$进制下的进位次数。

那么题目所求便是两个和不超过$N$的正整数,它们在$p$进制下做加法近位了至少$k$的可能方案数。

那么考虑数位$DP$,设$dp[i][j][0/1][0/1]$表示到了$p$进制下的第$i$位,进位次数为$j$,下一位是否进位,前$i$位是否与$N$在$p$进制下相同的方案。

时间复杂度:$\Theta(S^2)$设$S$为$N$在$p$进制下的位数。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
char ch[1001];
long long N[1001],S[1001];
long long p,k;
long long dp[1001][1001][2][2];
long long ans;
int main()
{
scanf("%s%lld%lld",ch+1,&p,&k);
N[0]=strlen(ch+1);
for(int i=1;i<=N[0];i++)N[i]=ch[i]-'0';
for(int i=1;(i<<1)<=N[0];i++)
N[i]^=N[N[0]-i+1]^=N[i]^=N[N[0]-i+1];
while(N[0])
{
for(int i=N[0];i;i--)
{
if(i>1)N[i-1]+=N[i]%p*10;
else S[++S[0]]=N[i]%p;
N[i]/=p;
}
while(N[0]&&!N[N[0]]){N[0]--;if(N[0]<0){puts("0");return 0;}}
}
dp[0][0][0][0]=1;
for(int i=1;i<=S[0];i++)
for(int j=0;j<=i;j++)
{
dp[i][j][0][0]=(((S[i]+1)*(S[i]+2)>>1)%1000000007*dp[i-1][j][0][0]%1000000007+(S[i]*(S[i]+1)>>1)%1000000007*(dp[i-1][j][0][1]+dp[i-1][j][1][0])%1000000007+(S[i]*(S[i]-1)>>1)%1000000007*dp[i-1][j][1][1]%1000000007)%1000000007;
dp[i][j+1][0][1]=((((p<<1)-S[i]-2)*(S[i]+1)>>1)%1000000007*dp[i-1][j][0][0]%1000000007+(((p<<1)-S[i])*(S[i]+1)>>1)%1000000007*dp[i-1][j][0][1]%1000000007+(((p<<1)-S[i]-1)*S[i]>>1)%1000000007*dp[i-1][j][1][0]%1000000007+(((p<<1)-S[i]+1)*S[i]>>1)%1000000007*dp[i-1][j][1][1]%1000000007)%1000000007;
dp[i][j][1][0]=(((S[i]+p+2)*(p-S[i]-1)>>1)%1000000007*dp[i-1][j][0][0]%1000000007+((p+S[i])*(p-S[i]-1)>>1)%1000000007*dp[i-1][j][0][1]%1000000007+((p+S[i]+1)*(p-S[i])>>1)%1000000007*dp[i-1][j][1][0]%1000000007+((p+S[i]-1)*(p-S[i])>>1)%1000000007*dp[i-1][j][1][1]%1000000007)%1000000007;
dp[i][j+1][1][1]=(((p-S[i]-2)*(p-S[i]-1)>>1)%1000000007*dp[i-1][j][0][0]%1000000007+((p-S[i])*(p-S[i]-1)>>1)%1000000007*(dp[i-1][j][0][1]+dp[i-1][j][1][0])%1000000007+((p-S[i]+1)*(p-S[i])>>1)%1000000007*dp[i-1][j][1][1]%1000000007)%1000000007;
}
for(int i=k;i<=S[0];i++)
ans=(ans+dp[S[0]][i][0][0])%1000000007;
printf("%lld",ans);
return 0;
}

rp++

[CSP-S模拟测试]:密码(数位DP+库默尔定理)的更多相关文章

  1. CF582D Number of Binominal Coefficients 库默尔定理 数位dp

    LINK:Number of Binominal Coefficients 原来难题都长这样.. 水平有限只能推到一半. 设\(f(x)\)表示x中所含p的最大次数.即x质因数分解之后 p的指标. 容 ...

  2. [CSP-S模拟测试]:密码(AC自动机+DP)

    题目传送门(内部题19) 输入格式 第一行两个正整数$n,k$,代表秘钥个数和要求.接下来两个正整数$x$和$y$,意义如题所述.接下来$n$行,每行一个正整数,意义如题所述. 输出格式 一个正整数, ...

  3. 2018.06.26 NOIP模拟 号码(数位dp)

    题目背景 SOURCE:NOIP2015-GDZSJNZX(难) 题目描述 Mike 正在在忙碌地发着各种各样的的短信.旁边的同学 Tom 注意到,Mike 发出短信的接收方手机号码似乎都满足着特别的 ...

  4. 2018.08.18 NOIP模拟 game(数位dp)

    Game 题目背景 SOURCE:NOIP2015-SHY4 题目描述 Alice 和 Bob 正在玩一个游戏,两个人从 1 轮流开始报数,如果遇到 7 的倍数或者遇到的这个数的十进制表示中含 7 , ...

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

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

  6. scauoj 18025 小明的密码 数位DP

    18025 小明的密码 时间限制:4000MS  内存限制:65535K提交次数:0 通过次数:0 题型: 编程题   语言: G++;GCC Description 小明的密码由N(1<=N& ...

  7. [CSP-S模拟测试]:B(DP+数学)

    题目传送门(内部题45) 输入格式 第一行$3$个整数$n,m,P$.第二行$m$个整数,表示$m$次询问. 输出格式 一行$m$个整数表示答案. 样例 样例输入1: 2 4 40 1 2 3 样例输 ...

  8. [CSP-S模拟测试]:蛇(DP+构造+哈希)

    题目传送门(内部题140) 输入格式 前两行有两个长度相同的字符串,描述林先森花园上的字母. 第三行一个字符串$S$. 输出格式 输出一行一个整数,表示有多少种可能的蛇,对$10^9+7$取模. 样例 ...

  9. [CSP-S模拟测试]:最小值(DP+乱搞)

    题目背景 $Maxtir$更喜欢序列的最小值. 题目传送门(内部题128) 输入格式 第一行输入一个正整数$n$和四个整数$A,B,C,D$. 第二行输入$n$个整数,第$i$个数表示$a_i$. 输 ...

随机推荐

  1. 服务端相关知识学习(五)之Zookeeper leader选举

    在上一篇文章中我们大致浏览了zookeeper的启动过程,并且提到在Zookeeper的启动过程中leader选举是非常重要而且最复杂的一个环节.那么什么是leader选举呢?zookeeper为什么 ...

  2. O026、Nova组件详解

    参考https://www.cnblogs.com/CloudMan6/p/5436855.html   本节开始,我们将详细讲解 Nova 的各个子服务.   前面架构概览一节知道 Nova 有若干 ...

  3. 1如何给devexpress的gridview控件绘制全选按钮

    1 首先注册gridview的this.edibandedGridView.CustomDrawColumnHeader += EdibandedGridView_CustomDrawColumnHe ...

  4. 解决docker pull 速度慢问题

    解决docker pull 速度慢问题 将docker镜像源修改为国内的: 在 /etc/docker/daemon.json 文件中添加以下参数(没有该文件则新建): { "registr ...

  5. 6.声明式异常处理、I18N

    声明式异常处理 1.在Action 中进行异常映射 <exception-mapping result="error" exception="java.sql.SQ ...

  6. 7、TortoiseSVN

    7.TortoiseSVN TortoiseSVN图标介绍: 目录空白处右键→TortoiseSVN→Settings 7.1独立将工程上传到服务器的思路 12.2针对archetype-catalo ...

  7. 第十章、random模块

    目录 第十章.random模块 第十章.random模块 #随机生成0-1之间的小数 import random print(random.random()) print(random.randint ...

  8. XML基础综合案例【三】

    实现简单的学生管理系统 使用xml当做数据,存储学生信息 ** 创建一个xml文件,写一些学生信息 ** 增加操作1.创建解析器2.得到document 3.获取到根节点4.在根节点上面创建stu标签 ...

  9. C/C++常见问题汇总

    问题1.数组和指针的区别 数组名不可以作为左值 char * p1 = "Hello World" ; //分配字符串常量,然后赋给 p1 ,一个指针型变量,是左值 ] = &qu ...

  10. kotlin字符串和数字之间的转换和人机交互

    继续基础学习~ 字符串和数字之间的转换 那如何转换呢,其实很简单: 编译木有报错,但是运行: 所以这里了解下. 人机交互 看这标题貌似高端的,其实也就是程序可以接受键盘的输入啦,下面开始: 首先提示用 ...