[CSP-S模拟测试]:密码(数位DP+库默尔定理)
题目描述
为了揭穿$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+库默尔定理)的更多相关文章
- CF582D Number of Binominal Coefficients 库默尔定理 数位dp
LINK:Number of Binominal Coefficients 原来难题都长这样.. 水平有限只能推到一半. 设\(f(x)\)表示x中所含p的最大次数.即x质因数分解之后 p的指标. 容 ...
- [CSP-S模拟测试]:密码(AC自动机+DP)
题目传送门(内部题19) 输入格式 第一行两个正整数$n,k$,代表秘钥个数和要求.接下来两个正整数$x$和$y$,意义如题所述.接下来$n$行,每行一个正整数,意义如题所述. 输出格式 一个正整数, ...
- 2018.06.26 NOIP模拟 号码(数位dp)
题目背景 SOURCE:NOIP2015-GDZSJNZX(难) 题目描述 Mike 正在在忙碌地发着各种各样的的短信.旁边的同学 Tom 注意到,Mike 发出短信的接收方手机号码似乎都满足着特别的 ...
- 2018.08.18 NOIP模拟 game(数位dp)
Game 题目背景 SOURCE:NOIP2015-SHY4 题目描述 Alice 和 Bob 正在玩一个游戏,两个人从 1 轮流开始报数,如果遇到 7 的倍数或者遇到的这个数的十进制表示中含 7 , ...
- [bzoj3209][花神的数论题] (数位dp+费马小定理)
Description 背景众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦.描述话说花神这天又来讲课了.课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了. ...
- scauoj 18025 小明的密码 数位DP
18025 小明的密码 时间限制:4000MS 内存限制:65535K提交次数:0 通过次数:0 题型: 编程题 语言: G++;GCC Description 小明的密码由N(1<=N& ...
- [CSP-S模拟测试]:B(DP+数学)
题目传送门(内部题45) 输入格式 第一行$3$个整数$n,m,P$.第二行$m$个整数,表示$m$次询问. 输出格式 一行$m$个整数表示答案. 样例 样例输入1: 2 4 40 1 2 3 样例输 ...
- [CSP-S模拟测试]:蛇(DP+构造+哈希)
题目传送门(内部题140) 输入格式 前两行有两个长度相同的字符串,描述林先森花园上的字母. 第三行一个字符串$S$. 输出格式 输出一行一个整数,表示有多少种可能的蛇,对$10^9+7$取模. 样例 ...
- [CSP-S模拟测试]:最小值(DP+乱搞)
题目背景 $Maxtir$更喜欢序列的最小值. 题目传送门(内部题128) 输入格式 第一行输入一个正整数$n$和四个整数$A,B,C,D$. 第二行输入$n$个整数,第$i$个数表示$a_i$. 输 ...
随机推荐
- C#面向对象20 序列化和反序列化
序列化和反序列化 序列化是把一个内存中的对象的信息转化成一个可以持久化保存的形式,以便于保存或传输,序列化的主要作用是不同平台之间进行通信,常用的有序列化有json.xml.文件等 一.序列化为j ...
- VPS磁盘划分建立新磁盘
今天我们来教下大家拿到VPS后,如何划分电脑内的磁盘空间.很多朋友可能遇到拿到VPS,为什么会打开电脑后在电脑盘那看到就一个C盘.还有些用户以为怎么只有那小的磁盘空间啊!怎么和卖的不一样啊!其实了我们 ...
- Resource Model
API不应该直接返回Entity,应该是返回一个Resource,不想把entity内部的细节暴漏给外部 viewModel是在MVC中的叫法 使用AutoMapper来对Entity和Resourc ...
- 转:git上传本地项目到github
转自:https://blog.csdn.net/Lucky_LXG/article/details/77849212 将本地项目上传到Github(两种简单.方便的方法) 一.第一种方法:首先你需要 ...
- js jquery 动态添加表格
for循环将你要添加的标签写上,然后直接var talbeAdd=""for(){ tableAdd+="<tr><td>这儿写你要添加的内容&l ...
- webpack升级4出现的问题
webpack3升级到4出现了很多问题,经过验证报错信息如下 1 Module parse failed: Unexpected token (:) You may need an appropria ...
- c++中cin和cout的用法
cin和cout是c++中的标准输入输出流. 一.cin cin的一般用法: cin>>变量a>>变量b>>变量c; cin会自动辨别变量的类型,如a可以是char ...
- Eclipse里导入Mybatis源码工程
打开Eclipse,在前两天的记录里我已经把Maven什么的都配置好了,还有Mybatis的源码也下载下来了,不相信的话可以去看一下我之前的记录:) OK. Mybatis源码解压之后是一个标准的Ma ...
- $'\r': command not found
在Linux下执行程序最省事的方式就是将系统的执行流程封装成一个shell脚本,上传到linux环境中后就可以直接执行了,但是今天在具体实施的时候出现了错误 $'\r': command not fo ...
- Gradle 配置国内镜像
项目级配置 在项目中找到如下文件 打开,添加上阿里云镜像 maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}