HDU3398—String-(组合数)
Problem Description
Recently, lxhgww received a task : to generate strings contain '0's and '1's only, in which '0' appears exactly m times, '1' appears exactly n times. Also, any prefix string of it must satisfy the situation that the number of 1's can not be smaller than the number of 0's . But he can't calculate the number of satisfied strings. Can you help him?
Input
T(T<=100) in the first line is the case number.
Each case contains two numbers n and m( 1 <= m <= n <= 1000000 ).
Output
Output the number of satisfied strings % 20100501.
Sample Input
1
2 2
Sample Output
2
Author
lxhgww
Source
HDOJ Monthly Contest – 2010.05.01
Recommend
lcy
题意为一个字符串只由0,1组成,且0有m个,1有n个,要求该字符串中任意的前缀中1的个数不能小于0的个数,问这样的字符串一共有多少个。结果对20100501取模。
将构造字符串的过程转化到二维坐标上去,1用y表示,0用x表示,从坐标(0,0)出发,0代表向右走(x增加),1代表向上走(y增加),因为0有m个,1有n个,所以最后到达的坐标为
(m,n) ,单纯考虑从0,0走到m,n一共有C(n+m,m)种方法,又因为任意前缀中1的个数不能小于0,所以y>=x,也就是合法走的路线经过的坐标要么在y=x上,要么在其上边,那么
不合法的路线经过的坐标则满足y<x,也就是路线不能与y=x-1相交,因为只要一相交,就不满足1的个数不能小于0的个数。
所以不合法的路径一定与y=x-1相交,找到(0,0)关于y=x-1的对称点(1,-1),从(1,-1)走到(m,n)一定与直线y=x-1相交,因为m,n在该直线的上边,1,-1在该直线的下
边。在这里设交点为P,那么路线就以P为分割点可以分为两部分,上面一部分取个名字叫不合法路线,下面一部分取个名字叫合法路线。那么从1,-1走到m,n有多少种方法也就
是从0,0走到m,n的不合法的方法数。仔细想一想为什么呢?为什么要找对称点,在对称直线一侧走的路线总可以在另一侧找到路线与之对称,刚才我们从1,-1走到m,n的那一段
合法路线沿着y=x-1再对称过去,不合法路线就不用对称了,因为不合法路线已经与y=x-1相交了(其实那一段合法路线的最后一个点也与y=x-1相交),这样就有了从0,0到m,n
的一种方案,总的来说就是对于从1,-1到m,n的每一条路线,都有从0,0到m,n关于y=x-1对称的一条路线与之对应。从1,-1走到m,n方法数为C (m+n,m-1)。
所以本题的答案就是C(n+m,m) - C (m+n,m-1)。
那么接下来的问题就是求上面的式子了。
上面式子最终可以化为 (n+1-m)*(n+m)! / (m! *(n+1)!)
直接求肯定不行,因为涉及到了除法的取模运算。
考虑整数唯一分解定理:
任意正整数都有且只有一种方式写出其素因子的乘积表达式。
A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn) 其中pi均为素数
那么可以把每个数都化成这样的形式,然后上下对于相同的素因子进行约分,也就是指数相减,对于一个素数pi,我们只要知道最终pi的指数是多少就可以了(上下都约分后的指数)
还有把阶层看作一个数,比m! 怎样求m!里面素数2的指数呢?
cnt=0; while(m) { m/=2; cnt+=m; } 就可以了,为什么呢?考虑m=4,则m!= 4*3*2*1, 第一次m/=2,是计算m!里面有多少个数能整除2的(有4,2),所以cnt+=2,有两个数贡献了两个素数2,接下来第二次m/=2,是计算m!里面有多少个数能整除4的,有1个数又贡献了一个素数2.
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1000000;
const int mod=20100501;
bool isprime[maxn*2+10];
int prime[maxn*2+10];
int len=0;//素数的个数
int n,m;
int t; void sieve(int n)//筛n以内的素数
{
for(int i=0;i<=n;i++)
isprime[i]=1;
isprime[0]=isprime[1]=0;
for(int i=2;i<=n;i++)
if(isprime[i])
{
prime[len++]=i;
for(int j=2*i;j<=n;j+=i)
isprime[j]=0;
}
} int cal(int p,int n)//计算n!里面有多少个p相乘
{
int ans=0;
while(n)
{
n/=p;
ans+=n;
}
return ans;
} int main()
{
sieve(maxn*2);
cin>>t;
while(t--)
{
long long ans=1;//记得要用long long
cin>>n>>m;
int nm=n+1-m;
for(int i=0;i<len&&prime[i]<=(n+m);i++)//prime[i]<=(n+m)是因为拆成素数幂相乘的形式该素数不会大于n+m,最大(n+m)! (n+m)*(n+m-1)*(n+m-2).....
{
int cnt=0;//分解为素数prime[i]的指数是多少
while(nm%prime[i]==0)//nm中有多少个prime[i],也就是把nm分解后prime[i]的指数
{
nm/=prime[i];
cnt++;
}
cnt=cnt+cal(prime[i],n+m)-cal(prime[i],m)-cal(prime[i],n+1);//加上分子的指数再减去分母的指数
for(int j=1;j<=cnt;j++)
{
ans=ans*prime[i];
if(ans>=mod)
ans%=mod;
}
}
cout<<ans<<endl;
}
return 0;
}
HDU3398—String-(组合数)的更多相关文章
- LCM性质 + 组合数 - HDU 5407 CRB and Candies
CRB and Candies Problem's Link Mean: 给定一个数n,求LCM(C(n,0),C(n,1),C(n,2)...C(n,n))的值,(n<=1e6). analy ...
- 计算一维组合数的java实现
背景很简单,就是从给定的m个不同的元素中选出n个,输出所有的组合情况! 例如:从1到m的自然数中,选择n(n<=m)个数,有多少种选择的组合,将其输出! 本方案的代码实现逻辑是比较成熟的方案: ...
- C++单元测试 之 gtest -- 组合数计算.
本文将介绍如何使用gtest进行单元测试. gtest是google单元测试框架.使用非常方便. 首先,下载gtest (有些google项目包含gtest,如 protobuf),复制目录即可使用. ...
- UOJ263 【NOIP2016】组合数问题
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- 2014多校第六场 1007 || HDU 4927 Series 1(杨辉三角组合数)
题目链接 题意 : n个数,每操作一次就变成n-1个数,最后变成一个数,输出这个数,操作是指后一个数减前一个数得到的数写下来. 思路 : 找出几个数,算得时候先不要算出来,用式子代替,例如: 1 2 ...
- codeforces 630F Selection of Personnel(组合数)
F. Selection of Personnel time limit per test 0.5 seconds memory limit per test 64 megabytes input s ...
- hdu 3944 DP? 组合数取模(Lucas定理+预处理+帕斯卡公式优化)
DP? Problem Description Figure 1 shows the Yang Hui Triangle. We number the row from top to bottom 0 ...
- nyoj 32 组合数【简单dfs】
组合数 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 找出从自然数1.2.... .n(0<n<10)中任取r(0<r<=n)个数的所有组合 ...
- HDU 5396 Expression(DP+组合数)(详解)
题目大意: 给你一个n然后是n个数. 然后是n-1个操作符,操作符是插入在两个数字之间的. 由于你不同的运算顺序,会产生不同的结果. 比如: 1 + 1 * 2 有两种 (1+1)*2 或者 ...
- 深搜最基础题---全排列And组合数
这个是理解标记和取消标记,用一个vis数组来标记 全排列代码: #include <stdio.h> ]; ]; int n; void dfs(int step)//step是当前已经进 ...
随机推荐
- python-day1(学前了解)
Markdown基本语法 各级标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 加粗 **加粗文本** 斜体 *我斜了* 高亮 ==我高亮了== 上标 2 ...
- Codeforce1196_D_F
D RGB Substring 题意 给定一个只含RGB三种字符的字符串,问最少修改多少个字符,能使得修改后的字符串存在一个长度为\(k\)的子串是...RGBRGB...这个循环字符串的子串. 分析 ...
- C++ 内联函数 inline关键字
inline 关键字主要功能是为了 代替掉 宏代码片段. 在C++中使用关键字inline关键字声明内联函数. inline int fun(int a,int b) { return a < ...
- JavaSE--类与对象
一.类 类是具有相同特性(数据元素)和行为(功能)的对象的抽象就是类.因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象,类实际上就是一种数据类型.类具有属性,它是对象的状态的抽象,用数 ...
- 外壳程序(shell):命令解释器commond
在Linux系统中有好几种shell,常见的有:ash.bash.zsh.ksh.tcsh等,计算机一般默认的是bash,使用命令echo $SHELL可以看出我们使用的哪种shell
- 093、如何用Graylog 管理日志? (2019-05-17 周五)
参考https://www.cnblogs.com/CloudMan6/p/7821817.html 上节我们已经部署好了 Graylog ,现在学习如何使用他来管理日志. 首先运行测试容器, ...
- springboot中的编码设置
在springboot中编码配置可以通过filter也可以通过springboot的核心配置文件application.properties中配置如下信息: #配置字符编码spring.http.en ...
- 使用Vim打开十六进制的文件
So Easy 这里使用打开 Hello.class 文件为例 首先使用 vim -b Hello.class 打开文件,然后在 Vim 的命令模式下输入 :%!xxd 回车即可看见文件内容. 效果: ...
- [转载]排序:长度为n的数组乱序存放着0至n-1. 现在只能进行0与其他数的swap
长度为n的数组乱序存放着0至n-1. 现在只能进行0与其他数的swap 请设计并实现排序. google笔试小题.题目来源:http://wenku.baidu.com/view/5aa818dda5 ...
- 6U VPX 加固智能计算异构服务器
6U VPX 加固智能计算异构服务器 北京太速科技有限公司在线客服:QQ:448468544 公司网站:www.orihard.com联系电话:15084122580