BZOJ4737 组合数问题 【Lucas定理 + 数位dp】

题目

组合数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} {n \mod k^i \choose m \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;
}

原文地址:https://www.cnblogs.com/Mychael/p/8971840.html

时间: 2024-08-09 12:35:59

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

bzoj 1902: Zju2116 Christopher lucas定理 &amp;&amp; 数位DP

1902: Zju2116 Christopher Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 172  Solved: 67[Submit][Status][Discuss] Description 给定n个元素,要从中间选择m个元素有多少种方案呢?答案很简单,就是C(n,m).如果一个整数m(0≤m≤n),C(n,m)是某一个质数p的倍数,那么这个m就是讨厌的数字,现在给定了p和n,求有多少个讨厌的数字. Input 第一行是一个正整数n,(1

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

题目描述 在一个\(k\)维空间中,每个整点被黑白染色.对于一个坐标为\((x_1,x_2,\ldots,x_k)\)的点,他的颜色我们通过如下方式计算: 如果存在一维坐标是\(0\),则颜色是黑色. 如果这个点是\((1,1,\ldots,1)\)(每一维都是\(1\)),这个点的颜色是白色 如果这个点的\(k\)个前驱(任取一维坐标减\(1\))中的白点有奇数个,那么这个点的颜色就是白色,否则就是黑色 给出一个\(k\)维超矩形,求这个矩形内的白点个数. \(k\leq 9,1\leq l_

[Swust OJ 247]--皇帝的新衣(组合数+Lucas定理)

题目链接:http://acm.swust.edu.cn/problem/0247/ Time limit(ms): 1000 Memory limit(kb): 65535 Description 在很久很久以前,有个臭美国王.一天,他得到了一件新衣,于是决定巡城看看老百姓的反应(囧).于是他命令可怜的宰相数一下他有多少种巡城方案. 城市是一个N*M的矩形,(N+1)*(M+1)条街把城市分成了N*M块.国王从左下角出发,每次只能向右或向上走,右上角是终点. 请你帮帮可怜的宰相. Input

【bzoj2111】[ZJOI2010]Perm 排列计数 dp+Lucas定理

题目描述 称一个1,2,...,N的排列P1,P2...,Pn是Mogic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Mogic的,答案可能很大,只能输出模P以后的值 输入 输入文件的第一行包含两个整数 n和p,含义如上所述. 输出 输出文件中仅包含一个整数,表示计算1,2,?, n的排列中, Mogic排列的个数模 p的值. 样例输入 20 23 样例输出 16 题解 dp+Lucas定理 题目显然小根堆,考虑怎么求以一个节点为根的方案数.根肯定

【bzoj3782】上学路线 dp+容斥原理+Lucas定理+中国剩余定理

题目描述 小C所在的城市的道路构成了一个方形网格,它的西南角为(0,0),东北角为(N,M).小C家住在西南角,学校在东北角.现在有T个路口进行施工,小C不能通过这些路口.小C喜欢走最短的路径到达目的地,因此他每天上学时都只会向东或北行走:而小C又喜欢走不同的路径,因此他问你按照他走最短路径的规则,他可以选择的不同的上学路线有多少条.由于答案可能很大,所以小C只需要让你求出路径数mod P的值. 输入 第一行,四个整数N.M.T.P. 接下来的T行,每行两个整数,表示施工的路口的坐标. 输出 一

lucas定理计算组合数

lucas定理计算组合数 C(n,k)有多种解法,1,dp递推:2,直接计算:3,lucas定理 lucas定理适合组合数取余数的计算,n和k的范围可到10^18 1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<algorithm> 6 7 using namespace std; 8 9 const int ma

多校杭电5794 大组合数(lucas)+dp

Problem Description There is a n×m board, a chess want to go to the position (n,m) from the position (1,1).The chess is able to go to position (x2,y2) from the position (x1,y1), only and if only x1,y1,x2,y2 is satisfied that (x2−x1)2+(y2−y1)2=5, x2>x

【日常学习】【组合数取模Lucas定理】HDU3037 Saving Beans题解

[提前声明:此题没有通过!WA!有待进一步研究修改.放在这里只是起一个例子的作用,其实这道题鄙人并没有真正掌握= =]. [本文努力抄袭模仿了小花妹妹的博文0戳我0)] 题目大意:共T个测试点,每个测试点中,给定n.m,求将不超过m个种子放入n个坑的方案总数,最后答案对质数p取模.(一共m个,每个坑放多少无所谓,最后没放完m个也无所谓) 数据范围:1 <= n, m <= 1000000000, 1 < p < 100000. 思路:原题意即求方程x1+-+xn=m解的个数,因为中

[CTSC2017][bzoj4903] 吉夫特 [状压dp+Lucas定理]

题面 传送门 思路 一句话题意: 给出一个长度为 n 的序列,求所有长度大于等于2的子序列个数,满足:对于子序列中任意两个相邻的数 a和 b (b 在 a 前面),\(C_a^b mod 2=1\),答案对1e9+7取模 显然膜2余1是个非常特殊的性质,应当好好加以利用 和组合数取模有关的东西,有Lucas定理,因此我们来试着推一推 \(C_n^m%2=C_{n%2}^{m%2}\ast C_{n/2}^{m/2}\) 这个玩意的意义,显然就是把n和m转成二进制,那么只要没有某一位上n是0m是1