hdu 3944 DP? (Lucas 定理)

仔细观察杨辉三角后可以发现从最高点到第n行第k个数的最短路为c(n+1,k);

根据Lucas定理可以求出,一般来说要求答案模去一个质数p且p的范围不大于10^5则可用Lucas.

Lucas(n,m,p)=cm(n%p,m%p)* Lucas(n/p,m/p,p)

Lucas(x,0,p)=1;

另外注意当k>n/2时,必须令k=n-k。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=10005;
int n,k,p;
int frc[1300][maxn];
int id[maxn];
bool vis[maxn];
int prim[maxn];
int cnt;
void init(){
    for(int i=2;i<maxn;i++)if(!vis[i]){
        prim[cnt]=i;
        id[i]=cnt;
        for(int j=i*2;j<maxn;j+=i)vis[j]=1;
        p=i;
        frc[cnt][0]=1;
        for(int j=1;j<p;j++)frc[cnt][j]=frc[cnt][j-1]*j%p;
        cnt++;
    }
}
int POW(int x,int n,int p){
    int res=1;
    while(n){
        if(n&1)res=res*x%p;
        x=x*x%p;
        n>>=1;
    }
    return res;
}
int cm(int n,int m,int p){
    if(m>n)return 0;
    int x=id[p];
    int ans=frc[x][n]*POW(frc[x][n-m]*frc[x][m]%p,p-2,p)%p;
    return ans;
}
int lucas(int n,int m,int p){
    if(m==0)return 1;
    int ans=cm(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
    return ans;
}
int main()
{
//    freopen("in","r",stdin);
    init();
    int cas=1;
    while(scanf("%d%d%d",&n,&k,&p)>0){
        if(k>n/2)k=n-k;
        int ans=lucas(n+1,k,p)+n-k;
        printf("Case #%d: %d\n",cas++,ans%p);
    }
    return 0;
}
时间: 2024-10-10 00:16:45

hdu 3944 DP? (Lucas 定理)的相关文章

hdu 3944 dp?

DP? Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 128000/128000 K (Java/Others)Total Submission(s): 1804    Accepted Submission(s): 595 Problem Description Figure 1 shows the Yang Hui Triangle. We number the row from top to bottom 0,1,2,-a

【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定理 题目显然小根堆,考虑怎么求以一个节点为根的方案数.根肯定

[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

bzoj 2111 [ZJOI2010]Perm 排列计数(DP+lucas定理)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2111 [题意] 给定n,问1..n的排列中有多少个可以构成小根堆. [思路] 设f[i]为以i为根的方案数,设l为左子树大小r为右子树大小,则有: f[i]=C(i-1,l)*f[l]*f[r] 因为是个堆,所以子树大小都是确定的,可以直接递推得到. 其中C(n,m) nm比较大,可以用lucas定理求. 模型建立的重要性可知一二... [代码] 1 #include<cstdio>

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

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

HDU 3037 Saving Beans 多重集合的结合 lucas定理

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3037 题目描述: 要求求x1 + x2 + x3 + ...... + xn <= m 非负整数解的个数, 结果对P取模, 输入的变量是n, m, p, P一定是素数 解题思路: x1 + ... + xn = m 非负整数解的个数是C(n+m-1, n) , 所以答案就是 C(n+0-1, 0) + C(n+1-1, 1) + ...... C(n+m-1, n) 对P取模, 由于组合数公式C(

HDU 3037 Saving Beans (Lucas定理)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3037 推出公式为C(n + m, m) % p, 用Lucas定理求大组合数取模的值 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int t; long long n, m, p; long long pow(long long n, long lo

组合数(Lucas定理) + 快速幂 --- HDU 5226 Tom and matrix

Tom and matrix Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=5226 Mean: 题意很简单,略. analyse: 直接可以用Lucas定理+快速幂水过的,但是我却作死的用了另一种方法. 方法一:Lucas定理+快速幂水过 方法二:首先问题可以转化为求(0,0),(n,m)这个子矩阵的所有数之和.画个图容易得到一个做法,对于n<=m,答案就是2^0+2^1+...+2^m=2^(m+1)-1,对于n>m

HDU 4349 Xiao Ming&#39;s Hope(数学题,Lucas定理)

解题思路: 深入理解lucas定理. Lucas定理:把n写成p进制a[n]a[n-1]a[n-2]...a[0],把m写成p进制b[n]b[n-1]b[n-2]...b[0],则C(n,m)与C(a[n],b[n])*C(a[n-1],b[n-1])*C(a[n-2],b[-2])*....*C(a[0],b[0])模p同余. 这题p为2,所以a[i]和b[i]为0或者1.又因为C(1,0), C(1,1), 即当n等于1时,结果才等于1. 所以写出n的二进制,m从0遍历到n,每一次遍历把m写