Codeforces 题目传送门 & 洛谷题目传送门

一道数论与数位 dp 结合的神题 %%%

首先在做这道题之前你需要知道一个定理:对于质数 \(p\) 及 \(n,k\),最大的满足 \(p^{\alpha}\mid\dbinom{n}{k}\) 的 \(\alpha\) 为 \(k\) 与 \(n-k\) 在 \(p\) 进制下相加的进位次数。证明就考虑扩展 Lucas 定理,记 \(f(x)\) 为最大的满足 \(p^{\alpha}\mid x\) 的 \(\alpha\),那么由 \(\dbinom{n}{k}=\dfrac{n!}{k!(n-k)!}\) 可知 \(f(\dbinom{n}{k})=f(n!)-f(k!)-f((n-k)!)\),我们考虑将 \(k,n-k\) 都在 \(k\) 进制下表示,我们设它们从高到低分别是 \(k=(a_{m-1}a_{m-2}\cdots a_1a_0)_p,n-k=(b_{m-1}b_{m-2}\cdots b_1b_0)_p,n=(c_{m-1}c_{m-2}\cdots c_1c_0)_p\)(在这里,我们不妨假设 \(n<p^m\),即 \(n+k\) 在 \(p^m\) 位不会产生进位),那么根据扩展 Lucas 定理 \(f(k!)\) 应当为 \(\sum\limits_{i=1}^{m-1}(a_{m-1}a_{m-2}\cdots a_i)_p\),即 \(k\) 在 \(p\) 进制表示下所有前缀(不包括本身)表示的数之和。很显然的一点是对于任意 \(i\in[1,m-1]\),\((a_{m-1}a_{m-2}\cdots a_i)_p+(b_{m-1}b_{m-2}\cdots b_i)_p\le(c_{m-1}c_{m-2}\cdots c_i)_p\),那么什么时候 \((a_{m-1}a_{m-2}\cdots a_i)_p+(b_{m-1}b_{m-2}\cdots b_i)_p<(c_{m-1}c_{m-2}\cdots c_i)_p\) 呢?显然如果前面没有进位那就不可能存在这种情况,否则,由于只有两数相加,因此最多进上来一位,而进上来一位以后显然就有 \((a_{m-1}a_{m-2}\cdots a_i)_p+(b_{m-1}b_{m-2}\cdots b_i)_p+1=(c_{m-1}c_{m-2}\cdots c_i)_p\),会对答案产生 \(1\) 的贡献,因此该结论成立。据说该结论有一个名字叫什么库默尔(Kummer)定理,不过名字啥的不重要啦((

知道这个结论之和就可以数位 dp 了。题目中 \(\alpha\le 10^9\) 是假的,如果 \(\alpha>\log_pA\) 那答案显然为 \(0\)。我们首先将题目给出的那个数用 \(p\) 进制表示,我们设 \(dp_{i,j,0/1,0/1}\) 表示考虑了最高的 \(i\) 位,当前进位了 \(j\) 次,上一位(第 \(i+1\) 高的位)是否产生进位,当前是否达到上界,考虑转移,假设 \(A\) 的第 \(i+1\) 位的值为 \(c\),我们要决策 \(k\) 的第 \(i+1\) 位的值 \(a\) 与 \(n-k\) 的第 \(i+1\) 位的值 \(b\),那么有转移:

  • \(dp_{i+1,j,0,0}\):

    • 如果从 \(dp_{i,j,0,0}\) 转移来那么需满足 \(a+b<p\),方案数 \(\dfrac{p(p+1)}{2}\)
    • 如果从 \(dp_{i,j,0,1}\) 转移来那么需满足 \(a+b<c\),方案数 \(\dfrac{c(c+1)}{2}\)
    • 如果从 \(dp_{i,j,1,0}\) 转移来那么需满足 \(a+b\ge p\),方案数 \(\dfrac{p(p-1)}{2}\)
    • 如果从 \(dp_{i,j,1,1}\) 转移来那么需满足 \(p\le a+b<p+c\),方案数 \(\dfrac{(p+c)(p+c+1)}{2}-\dfrac{p(p+1)}{2}=\dfrac{c(2n-c-1)}{2}\)
  • \(dp_{i+1,j,0,1}\):
    • 如果从 \(dp_{i,j,0,1}\) 转移来那么需满足 \(a+b=c\),方案数 \(c+1\)
    • 如果从 \(dp_{i,j,1,1}\) 转移来那么需满足 \(a+b=p+c\),方案数 \(p-c-1\)
  • \(dp_{i+1,j,1,0}\):
    • 如果从 \(dp_{i,j,0,0}\) 转移来那么需满足 \(a+b<p-1\),方案数 \(\dfrac{p(p-1)}{2}\)
    • 如果从 \(dp_{i,j,0,1}\) 转移来那么需满足 \(a+b<c-1\),方案数 \(\dfrac{c(c-1)}{2}\)
    • 如果从 \(dp_{i,j,1,0}\) 转移来那么需满足 \(a+b\ge p-1\),方案数 \(\dfrac{p(p+1)}{2}\)
    • 如果从 \(dp_{i,j,1,1}\) 转移来那么需满足 \(p\le a+b+1<p+c\),方案数 \(\dfrac{(p+c)(p+c-1)}{2}-\dfrac{p(p-1)}{2}=\dfrac{c(2n-c+1)}{2}\)
  • \(dp_{i+1,j,1,1}\):
    • 如果从 \(dp_{i,j,0,1}\) 转移来那么需满足 \(a+b+1=c\),方案数 \(c\)
    • 如果从 \(dp_{i,j,1,1}\) 转移来那么需满足 \(a+b+1=p+c\),方案数 \(p-c\)

算下贡献转移一下即可。时间复杂度 \(\mathcal O(\log^2_kA)\)。

最好使用滚动数组优化。

const int MAXL=4000;
const int MOD=1e9+7;
int n,alpha,len,m=0,a[MAXL+5],x[MAXL+5];
char A[MAXL+5];int dp[2][MAXL+5][2][2];
int main(){
scanf("%d%d%s",&n,&alpha,A+1);len=strlen(A+1);
if(alpha>MAXL) return puts("0"),0;
for(int i=1;i<=len;i++) a[len-i+1]=A[i]-'0';
while(len){
ll cur=0;
for(int i=len;i;i--){
cur=cur*10+a[i];a[i]=cur/n;cur%=n;
} x[++m]=cur;if(!a[len]) len--;
} int cur=1,pre=0;
dp[cur][0][0][1]=1;
for(int i=m;i;i--){
cur^=pre^=cur^=pre;
memset(dp[cur],0,sizeof(dp[cur]));
int c1=1ll*(n+1)*n/2%MOD;
int c2=1ll*(x[i]+1)*x[i]/2%MOD;
int c3=1ll*(n-1)*n/2%MOD;
int c4=1ll*x[i]*(n*2-x[i]-1)/2%MOD;
int c5=1ll*(x[i]-1)*x[i]/2%MOD;
int c6=1ll*x[i]*(n*2-x[i]+1)/2%MOD;
for(int j=0;j<=m-i+1;j++){
int f0=dp[pre][j][0][0],f1=dp[pre][j][0][1];
int f2=dp[pre][j][1][0],f3=dp[pre][j][1][1];
dp[cur][j][0][0]=(1ll*f0*c1+1ll*f1*c2+1ll*f2*c3+1ll*f3*c4)%MOD;
dp[cur][j][0][1]=(1ll*(x[i]+1)*f1+1ll*(n-x[i]-1)*f3)%MOD;
dp[cur][j+1][1][0]=(1ll*f0*c3+1ll*f1*c5+1ll*f2*c1+1ll*f3*c6)%MOD;
dp[cur][j+1][1][1]=(1ll*x[i]*f1+1ll*(n-x[i])*f3)%MOD;
}
} int ans=0;
for(int i=alpha;i<=m;i++){
ans=(ans+dp[cur][i][0][0])%MOD;
ans=(ans+dp[cur][i][0][1])%MOD;
} printf("%d\n",ans);
return 0;
}

Codeforces 582D - Number of Binominal Coefficients(Kummer 定理+数位 dp)的更多相关文章

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

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

  2. uoj86 mx的组合数 (lucas定理+数位dp+原根与指标+NTT)

    uoj86 mx的组合数 (lucas定理+数位dp+原根与指标+NTT) uoj 题目描述自己看去吧( 题解时间 首先看到 $ p $ 这么小还是质数,第一时间想到 $ lucas $ 定理. 注意 ...

  3. bzoj 1902: Zju2116 Christopher lucas定理 && 数位DP

    1902: Zju2116 Christopher Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 172  Solved: 67[Submit][Stat ...

  4. Codeforces Beta Round #51 D. Beautiful numbers(数位dp)

    题目链接:https://codeforces.com/contest/55/problem/D 题目大意:给你一段区间[l,r],要求这段区间中可以整除自己每一位(除0意外)上的数字的整数个数,例如 ...

  5. 【XSY2691】中关村 卢卡斯定理 数位DP

    题目描述 在一个\(k\)维空间中,每个整点被黑白染色.对于一个坐标为\((x_1,x_2,\ldots,x_k)\)的点,他的颜色我们通过如下方式计算: 如果存在一维坐标是\(0\),则颜色是黑色. ...

  6. BZOJ4737 组合数问题(卢卡斯定理+数位dp)

    不妨不管j<=i的限制.由卢卡斯定理,C(i,j) mod k=0相当于k进制下存在某位上j大于i.容易想到数位dp,即设f[x][0/1][0/1][0/1]为到第x位时是否有某位上j> ...

  7. BZOJ4591 SHOI2015超能粒子炮·改(卢卡斯定理+数位dp)

    注意到模数很小,容易想到使用卢卡斯定理,即变成一个2333进制数各位组合数的乘积.对于k的限制容易想到数位dp.可以预处理一发2333以内的组合数及组合数前缀和,然后设f[i][0/1]为前i位是否卡 ...

  8. codeforces 597div2 F. Daniel and Spring Cleaning(数位dp+二维容斥)

    题目链接:https://codeforces.com/contest/1245/problem/F 题意:给定一个区间(L,R),a.b两个数都是属于区间内的数,求满足 a + b = a ^ b ...

  9. Codeforces 914C Travelling Salesman and Special Numbers:数位dp

    题目链接:http://codeforces.com/problemset/problem/914/C 题意: 对数字x进行一次操作,可以将数字x变为x在二进制下1的个数. 显然,一个正整数在进行了若 ...

随机推荐

  1. mybatis学习笔记(2)基本原理

    引言在mybatis的基础知识中我们已经可以对mybatis的工作方式窥斑见豹(参考:<MyBatis----基础知识>).但是,为什么还要要学习mybatis的工作原理?因为,随着myb ...

  2. Spring Cloud Alibaba 的服务注册与发现

    Spring Cloud Alibaba 服务发现例子 一.需求 1.提供者完成的功能 2.消费者完成的功能 3.可以附加的额外配置 二.实现步骤 1.总的依赖引入 2.服务提供者和发现者,引入服务发 ...

  3. [NOIP模拟46]鼠树

    神仙题. 首先不考虑把黑点变白,发现每个白点的信息与它的归属点是相同的.可以在线段树中只维护黑点的信息,再记录$DFS$序上每个点之前黑点个数的前缀和,每次操作可以二分出该点的归属点进行操作. 具体维 ...

  4. binary-tree-maximum-path-sum leetcode C++

    Given a binary tree, find the maximum path sum. The path may start and end at any node in the tree. ...

  5. hdu 2955 Robberies(背包DP)

    题意: 小偷去抢银行,他母亲很担心. 他母亲希望他被抓的概率真不超过P.小偷打算去抢N个银行,每个银行有两个值Mi.Pi,Mi:抢第i个银行所获得的财产 Pi:抢第i个银行被抓的概率 求最多能抢得多少 ...

  6. void * 是什么?

    最近遇到void *的问题无法解决,发现再也无法逃避了(以前都是采取悄悄绕过原则),于是我决定直面它. 在哪遇到了? 线程创建函数pthread_create()的最后一个参数void *arg,嗯? ...

  7. ESP32-IDF安装并在VSCode上编译Hello World

    ESP32-IDF安装 准备工作 安装python 3 安装方法参考链接:https://blog.csdn.net/hg_qry/article/details/106415252 安装git 安装 ...

  8. HydroD:辅助脚本函数

    HydroD:辅助函数 在HydroD中,使用JS脚本可以快速进行模拟参数设置,但是经过尝试,HydroD中的JS脚本语言并不支持现在JavaScript中的一些语法.所以考虑采用Matlab字符串拼 ...

  9. Linux USB (目录)

    1.USB 总线简介 2.USB 协议分析 3.USB Host 详解 4.USB Device 详解 5.usbip (USB Over IP) 使用实例

  10. The 'stream().forEach()' chain can be replaced with 'forEach()' (may change semantics)

    对集合操作时,因不同的写法Idea经常会提示:The 'stream().forEach()' chain can be replaced with 'forEach()' (may change s ...