题目

组合数C(n,m)表示的是从n个物品中选出m个物品的方案数。举个例子,从(1,2,3)三个物品中选择两个物品可以有(

1,2),(1,3),(2,3)这三种选择方法。根据组合数的定义,我们可以给出计算组合数C(n,m)的一般公式:

C(n,m)=n!/m!*(n?m)!

其中n!=1×2×?×n。(额外的,当n=0时,n!=1)

小葱想知道如果给定n,m和k,对于所有的0≤i≤n,0≤j≤min(i,m)有多少对(i,j)满足C(i,j)是k的倍数。

输入格式

第一行有两个整数t,k,其中t代表该测试点总共有多少组测试数据,k的意义见。

接下来t行每行两个整数n,m,其中n,m的意义见。

输出格式

t行,每行一个整数代表所有的0≤i≤n,0≤j≤min(i,m)中有多少对(i,j))满足C(i,j)是k的倍数

答案对10^9+7取模。

输入样例

3 23

23333333 23333333

233333333 233333333

2333333333 2333333333

输出样例

851883128

959557926

680723120

提示

1≤n,m≤10^18,1≤t,k≤100,且 k 是一个质数

题解

根据\(Lucas\)定理我们知道,在模质数\(k\)下

\[{n \choose m} \equiv \prod_{i = 1} {\lfloor \frac{n}{k^{i - 1}} \rfloor \mod k^i \choose \lfloor \frac{m}{k^{i - 1}} \rfloor \mod k^i} \pmod k
\]

由此,结果为\(0\),当且仅当存在一个\(i\),使得\({n \mod k^i \choose m \mod k^i} \equiv 0 \pmod k\)

一个组合数在模质数意义下为0,当且仅当\(n < m\)

一个组合数在模质数意义下不为0,那么就是\(n >= m\)

那么我们将\(n\)和\(m\)拆分为\(k\)进制数,就可以设一个dp:

\(f[i][0/1][0/1]\)表示第\(i\)位之前(\(n\)是否达到上界) (\(m\)是否达到上界) 的\(n >= m\)方案数,即不为\(0\)的方案数

最后用总方案减去就可以了

转移就自己推推

要注意乘法可能溢出,要用快速乘

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
#define cls(s) memset(s,0,sizeof(s))
using namespace std;
const int maxn = 105,maxm = 100005,INF = 1000000000,P = 1e9 + 7;
LL n,m,f[maxn][2][2],a[maxn],b[maxn],ai,bi,N,K,v2;
LL qpow(LL a,LL b){
LL ans = 1;
for (; b; b >>= 1,a = a * a % P)
if (b & 1) ans = ans * a % P;
return ans;
}
void add(LL& a,LL b){
a += b;
if (a >= P) a -= P;
}
LL Mul(LL a,LL b){
LL re = 0;
for (; b; b >>= 1,a = (a + a) % P) if (b & 1) re = (re + a) % P;
return re;
}
LL S(LL x){return Mul(x,x + 1) * v2 % P;}
int main(){
int T; scanf("%d%lld",&T,&K); v2 = qpow(2,P - 2);
while (T--){
cls(a); cls(b); cls(f);
scanf("%lld%lld",&n,&m); ai = bi = 0;
LL ans = S(min(n,m) + 1);
ans = (ans + Mul(m + 1,max(n - m,0ll))) % P;
while (n) a[++ai] = n % K,n /= K;
while (m) b[++bi] = m % K,m /= K;
N = max(ai,bi);
f[N][1][1] = 1;
for (int i = N; i; i--){
//0 0
add(f[i - 1][0][0],S(K) * f[i][0][0] % P);
//0 1
add(f[i - 1][0][0] ,(S(b[i]) + b[i] * (K - b[i]) % P) % P * f[i][0][1] % P);
add(f[i - 1][0][1],(K - b[i]) * f[i][0][1] % P);
//1 0
add(f[i - 1][0][0],S(a[i]) * f[i][1][0] % P);
add(f[i - 1][1][0],(a[i] + 1) * f[i][1][0] % P);
//1 1
if (a[i] >= b[i]){
add(f[i - 1][0][0],(S(b[i]) + b[i] * ((a[i] - b[i] + P) % P) % P) % P * f[i][1][1] % P);
add(f[i - 1][1][0],b[i] * f[i][1][1] % P);
add(f[i - 1][0][1],(a[i] - b[i] + P) % P * f[i][1][1] % P);
add(f[i - 1][1][1],f[i][1][1]);
}
else {
add(f[i - 1][0][0],S(a[i]) * f[i][1][1] % P);
add(f[i - 1][1][0],(a[i] + 1) % P * f[i][1][1] % P);
}
}
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
ans = (ans - f[0][i][j] + P) % P;
printf("%lld\n",(ans % P + P) % P);
}
return 0;
}

BZOJ4737 组合数问题 【Lucas定理 + 数位dp】的更多相关文章

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

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

  2. [BZOJ4591][SHOI2015]超能粒子炮·改(Lucas定理+数位DP)

    大组合数取模可以想到Lucas,考虑Lucas的意义,实际上是把数看成P进制计算. 于是问题变成求1~k的所有2333进制数上每一位数的组合数之积. 数位DP,f[i][0/1]表示从高到低第i位,这 ...

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

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

  4. [UOJ 275/BZOJ4737] 【清华集训2016】组合数问题 (LUCAS定理的运用+数位DP)

    题面 传送门:UOJ Solution 这题的数位DP好蛋疼啊qwq 好吧,我们说回正题. 首先,我们先回忆一下LUCAS定理: \(C_n^m \equiv C_{n/p}^{m/p} \times ...

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

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

  6. 【NOI2019模拟2019.6.29】组合数(Lucas定理、数位dp)

    Description: p<=10且p是质数,n<=7,l,r<=1e18 题解: Lucas定理: \(C_{n}^m=C_{n~mod~p}^{m~mod~p}*C_{n/p} ...

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

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

  8. Codeforces 582D - Number of Binominal Coefficients(Kummer 定理+数位 dp)

    Codeforces 题目传送门 & 洛谷题目传送门 一道数论与数位 dp 结合的神题 %%% 首先在做这道题之前你需要知道一个定理:对于质数 \(p\) 及 \(n,k\),最大的满足 \( ...

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

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

随机推荐

  1. python剑指offer系列二叉树中和为某一值的路径

    题目描述 输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.(注意: 在返回值的list中,数组长度大 ...

  2. 题解 P1137 【旅行计划】

    传送门 很显然,每个点的答案是它所有前驱节点的答案加1,即f[i]=max(f[i],f[j]+1); 考虑空间复杂度用邻接表存图,在拓扑排序同时DP就好了 #include<iostream& ...

  3. c++ 中常量与变量 基本数据类型

    c++中常量如何分类? 1.整数常量,所有的整数. 整数又分为 int (integer) 占用4个字节 一个字节占几个二进制位?8个二进制位,一个整型变量占32位二进制位 (内存中开辟出来的存储空间 ...

  4. SummerVocation_Learning--StringBuffer类

    java.lang.StringBuffer代表可变的字符序列.与String类基本类似. 常见的构造方法: StringBuffer(),创建一个不包含字符序列的空的StringBuffer对象. ...

  5. Visual Studio 2017 初次体验

    在初次体验中遇到以下问题以及技巧 1. 在出现红色波浪线时为出现错误语法,将鼠标移动到相应位置可以获得相关错误信息 2.在编写代码过程中,行号上出现的小黄灯可以有提示信息 3.List 与 Array ...

  6. 新装NGINX重启,出现错误 nginx: [error] open() "/usr/local/nginx/logs/nginx.pid"

    重装nginx出现,重启出现错误 ./nginx -s reload nginx: [error] open() "/usr/local/nginx/logs/nginx.pid" ...

  7. DeepFaceLab报错,OOM如何解决?

    DeepFaceLab出错,虽然错误提示好几个屏幕,但是无非两种情况,一种是驱动没装好,一种是显存配置不够.上一篇文章说了驱动的问题,这一篇就说说配置不够的问题. 这个问题的表现形式,往往是各种OOM ...

  8. 动态规划:POJ2576-Tug of War(二维费用的背包问题)

    Tug of War Time Limit: 3000MS Memory Limit: 65536K Description A tug of war is to be arranged at the ...

  9. 牛客第四次多校Maximum Mode

    链接:https://www.nowcoder.com/acm/contest/142/G来源:牛客网 题目描述 The mode of an integer sequence is the valu ...

  10. TI C6000优化手册——让代码看起来像钉子

    DSP芯片的出现,是为了解决大量的数字运算问题.通过集成专用的加法器.乘法器.地址产生器.复杂逻辑等硬件单元,DSP能实现比普通单片机更快速的数字运算,使处理器更适用于实时性高.复杂度强的处理场合.也 ...