题意:有m个人有一张50元的纸币,n个人有一张100元的纸币。他们要在一个原始存金为0元的售票处买一张50元的票,问一共有几种方案数。

解法:(学习了他人的推导后~)

1.Catalan数的应用7的变形。(推荐阅读:http://www.cnblogs.com/chenhuan001/p/5157133.html)。P.S.不知我之前自己推出的公式“C(n,m)*C(2*m,m)/(m+1)*P(n,n)*P(m,m)”是否是正确的。

(1)在不考虑m人和n人本身组内的排列时,总方案数为C(m+n,n)或C(m+n,m)。

(2)而不合法的设1为50元(m个),0为100元(n个)。那么便有10110...设前2k+1个数中有k+1个0和k个1,因此不合法。而将2k+1之后的所有0(n-k-1个)和1(m-k个)异或。这样的转换是唯一对应的,不合法的方案数仍不会改变,因此可行,得到n-k-1个1和m-k个0。总共n-1个1和m+1个0。这样不合法的方案数就可用C(n+m,n-1)或C(n+m,m+1)表示了。

由于(1)-(2)已经包含了m人和n人跨组之间的组合,于是只乘上m人和n人本身组内的排列P(m,m)和P(n,n)表示答案,而不是P(n+m,n+m)。化简可得(m+n)! (m-n+1)/(m+1)。

2.隔板法。(不知道这个方法是不是这么叫......)

(1)先放了n个5元,构成n+1个空位。再一个个放m个100元,第一个,除了第1个空不可,其它位置都可放,合法的概率为n/(n+1)。第二个100元,概率变为(n-1)/n。以此类推,第m个的概率就是(n-m+1)/(n-m+2)。那么这m个100元的合法的总概率就是所有的概率相乘,得到(n-m+1)/(n+1)。

(2)然后再考虑这n+m个的排列方法P(n+m,n+m),与原来的相乘。

最终得到(n+m)!*(n-m+1)/(n+1).

 1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 using namespace std;
6 #define N 110
7
8 struct node
9 {
10 int s[510];
11 int l;
12 node() {l=0;memset(s,0,sizeof(s));}
13 };
14 node multi(node x,int y)//dif from +
15 {
16 node z;
17 z.l=x.l;
18 for (int i=1;i<=x.l;i++)
19 {
20 z.s[i]+=x.s[i]*y;
21 if (z.s[i]>9) z.s[i+1]+=z.s[i]/10,z.s[i]%=10;
22 }
23 while (z.s[z.l+1])
24 {
25 z.l++;
26 if (z.s[z.l]>9) z.s[z.l+1]+=z.s[z.l]/10,z.s[z.l]%=10;
27 }
28 return z;
29 }
30 node conv(node x)
31 {
32 node z;
33 z.l=x.l;
34 for (int i=1;i<=x.l;i++)
35 z.s[x.l-i+1]=x.s[i];
36 return z;
37 }
38 node div(node x,int y)
39 {
40 node z;
41 int t=x.l+1,h=0;
42 while (h<y && t>1) h=10*h+x.s[--t];
43 z.s[++z.l]=h/y,h%=y;
44 while (t>1)
45 {
46 h=10*h+x.s[--t];
47 z.s[++z.l]=h/y,h%=y;
48 }
49 z=conv(z);
50 return z;
51 }
52 /*另一种打法
53 node div(node x,int y)//crucial
54 {
55 node z;
56 int t=x.l+1,h=0;
57 while (t>1)//converse!
58 {
59 bool tf=true;
60 while (h<y && t>1)
61 {
62 h=10*h+x.s[--t];
63 if (!tf&&z.l) z.s[++z.l]=0;//商最高位之后才开始赋值0,并且要是加入新的一位为0
64 tf=false;
65 }
66 z.s[++z.l]=h/y,h%=y;
67 }
68 z=conv(z);
69 return z;
70 }
71 */
72 void print(node x)
73 {
74 for (int i=x.l;i>=1;i--)
75 printf("%d",x.s[i]);
76 printf("\n");
77 }
78 node P(int x)
79 {
80 node z;
81 z.l=z.s[1]=1;
82 for (int i=x;i>=1;i--)
83 z=multi(z,i);
84 return z;
85 }
86 int main()
87 {
88 int n,m;
89 while (1)
90 {
91 scanf("%d%d",&n,&m);
92 if (!n&&!m) break;
93 if (n<m) {printf("0\n");continue;}
94 print(div(multi(P(n+m),n-m+1),n+1));
95 }
96 return 0;
97 }

排列组合+高精度

3.动态规划。转载自:http://blog.csdn.net/clover_hxy/article/details/52931233

f[i][j]表示到第i个人,已经有j个人用50元买了门票。
f[i][j] = f[i-1][j] + f[i-1][j-1]; (当前这个人分别用100元或50元。同时用 k=i-j 表示100元的个数,递推时保证 k<=j。)
因为每个人是不一样的所以最后的答案是 f[n+m][n]*n!*m!。

P.S.看!DP一个状态递推就能省了上面2种一长串的头脑风暴推导过程,可见DP的优越性。

  1 #include<iostream>
2 #include<algorithm>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #define N 103
7 using namespace std;
8 struct data{
9 int num[403];
10 }f[N*2][N],ans;
11 int n,m,a[N],b[N],c[N];
12 int calc(int a[N],int x)
13 {
14 a[0]=1; a[1]=1;
15 for (int i=1;i<=x;i++)
16 {
17 for (int j=1;j<=a[0];j++)
18 a[j]*=i;
19 for (int j=1;j<=a[0];j++) {
20 a[j+1]+=a[j]/10000;
21 a[j]%=10000;
22 }
23 int t=a[0];
24 while (a[t+1]) {
25 t++;
26 a[t+1]+=a[t]/10000;
27 a[t]%=10000;
28 }
29 a[0]=t;
30 }
31 }
32 void add(data &x,data y,data z)
33 {
34 int t=max(y.num[0],z.num[0]);
35 for (int i=1;i<=t;i++)
36 x.num[i]=y.num[i]+z.num[i];
37 for (int i=1;i<=t;i++)
38 x.num[i+1]+=x.num[i]/10000,x.num[i]%=10000;
39 while (x.num[t+1]){
40 t++;
41 x.num[t+1]+=x.num[t]/10000;
42 x.num[t]%=10000;
43 }
44 x.num[0]=t;
45 }
46 void mul(data &x,int a[N])
47 {
48 memset(c,0,sizeof(c));
49 for (int i=1;i<=x.num[0];i++)
50 for (int j=1;j<=a[0];j++)
51 c[i+j-1]+=x.num[i]*a[j];
52 int t=max(x.num[0],a[0]);
53 for (int i=1;i<=t;i++)
54 c[i+1]+=c[i]/10000,c[i]%=10000;
55 while(c[t+1]) {
56 t++;
57 c[t+1]+=c[t]/10000;
58 c[t]%=10000;
59 }
60 c[0]=t;
61 for (int i=0;i<=c[0];i++) x.num[i]=c[i];
62 }
63 int main()
64 {
65 freopen("a.in","r",stdin);
66 freopen("my.out","w",stdout);
67 int n=100; int m=100;
68 f[0][0].num[0]=1;
69 f[0][0].num[1]=1;
70 for (int i=1;i<=n+m;i++)
71 for (int j=min(i,n);j>=1;j--)
72 {
73 int k=(i-j);
74 if (k>j) break;
75 add(f[i][j],f[i-1][j],f[i-1][j-1]);
76 }
77 int cnt=0;
78 while (true){
79 scanf("%d%d",&n,&m); cnt++;
80 if (n==0&&m==0) break;
81 memset(a,0,sizeof(a));
82 memset(b,0,sizeof(b));
83 calc(a,n); calc(b,m);
84 for (int i=0;i<=400;i++) ans.num[i]=0;
85 for (int i=0;i<=f[n+m][n].num[0];i++)
86 ans.num[i]=f[n+m][n].num[i];
87 mul(ans,a); mul(ans,b);
88 printf("Test #%d:\n",cnt);
89 if (ans.num[0]==0||n<m) {
90 printf("0\n");
91 continue;
92 }
93 for (int i=ans.num[0];i>=1;i--){
94 int t=ans.num[i];
95 if (i!=ans.num[0]){
96 if (t<10) printf("000");
97 else if (t<100) printf("00");
98 else if (t<1000) printf("0");
99 }
100 printf("%d",t);
101 }
102 printf("\n");
103 }
104 }

DP+压位高精度

【noi 2.6_9288】&【hdu 1133】Buy the Ticket(DP / 排列组合 Catalan+高精度除法)的更多相关文章

  1. hdu 1133 Buy the Ticket(Catalan)

    Buy the Ticket Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T ...

  2. hdu 1133 Buy the Ticket (大数+递推)

    Buy the Ticket Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

  3. HDU——1133 Buy the Ticket

    Buy the Ticket Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T ...

  4. HDU 1133 Buy the Ticket (数学、大数阶乘)

    Buy the Ticket Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

  5. hdu 1133 Buy the Ticket

    首先,记50的为0,100的为1. 当m=4,n=3时,其中的非法序列有0110010; 从不合法的1后面开始,0->1,1->0,得到序列式0111101 也就是说,非法序列变为了n-1 ...

  6. HDOJ/HDU 1133 Buy the Ticket(数论~卡特兰数~大数~)

    Problem Description The "Harry Potter and the Goblet of Fire" will be on show in the next ...

  7. HDU 1133 Buy the Ticket 卡特兰数

    设50元的人为+1 100元的人为-1 满足前随意k个人的和大于等于0 卡特兰数 C(n+m, m)-C(n+m, m+1)*n!*m! import java.math.*; import java ...

  8. HDU 4043 FXTZ II (组合数学-排列组合)

    FXTZ II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Su ...

  9. HDU 5151 Sit sit sit 区间DP + 排列组合

    Sit sit sit 问题描述 在一个XX大学中有NN张椅子排成一排,椅子上都没有人,每张椅子都有颜色,分别为蓝色或者红色. 接下来依次来了NN个学生,标号依次为1,2,3,...,N. 对于每个学 ...

随机推荐

  1. Java 使用拦截器无限转发/重定向无限循环/重定向次数过多报错(StackOverflowError) 解决方案

    说明:当使用拦截器出现"请求转发"无限循环或者"重定向"次数过多这种问题的时候,一般都是 拦截器 设置错了 情况一:请求转发时没有配置排除拦截路径,就是说你访问 ...

  2. wpf 通过为DataGrid所绑定的数据源类型的属性设置Attribute改变DataGrid自动生成列的顺序

    环境Win10 VS2019 .Net Framework4.8 在wpf中,如果为一个DataGrid绑定到一个数据源,默认情况下DataGrid会为数据源类型的每个属性生成一个列(Column)对 ...

  3. EGADS框架处理流程分析

    最近在搞异常检测相关的工作,因此调研了业界常用的异常检测系统.通过查阅相关资料,发现业界对雅虎开源的EGADS系统评价比较高,其git项目已有980个star.这周阅读了项目的源码,梳理了系统框架的基 ...

  4. 2.jmeter组件介绍

    jmeter默认语言设置:  1.临时设置: 进入options -- Choose Language -- 选择中文简体,设置后语言  切换成中文,重启失效  2.永久设置:进入jmeter目录下的 ...

  5. Java并发包源码学习系列:挂起与唤醒线程LockSupport工具类

    目录 LockSupport概述 park与unpark相关方法 中断演示 blocker的作用 测试无blocker 测试带blocker JDK提供的demo 总结 参考阅读 系列传送门: Jav ...

  6. 配置 Docker 镜像加速源地址

    docker 安装官方文档 根据实例的操作系统类型,参考相应的文档进行安装. 查看 linux 是 CentOS 还是 Ubuntu uname -a #查看系统信息 lsb_release -a # ...

  7. ctfshow—web—web4

    打开靶机 发现与web3很相似,测试文件包含未成功 此题有两种解决方法 一.日志注入 查看日志的默认目录,得到了日志文件 ?url=/var/log/nginx/access.log 进行日志注入 & ...

  8. Android事件分发机制三:事件分发工作流程

    前言 很高兴遇见你~ 本文是事件分发系列的第三篇. 在前两篇文章中,Android事件分发机制一:事件是如何到达activity的? 分析了事件分发的真正起点:viewRootImpl,Activit ...

  9. Redis二进制安全

    为了便于理解,举一个例子: 在很多编辑器中,都会默认/n是换行字符,也就意味着一串字符存进去,涉及/n都会做一个默认的转义处理,这在编辑语言中,C也有这个特性,例如字符串Hello,\0 World! ...

  10. .NET, NETCORE 怎么写 "超时"代码,解析"超时"代码原理!

    干货:本人不会长篇大论.能贴上去的,就是干货,能用一两句话讲明白的,不会大讲概念,不会浪费大家宝贵的时间. 前言:我们发现,超时是个非常重要的概念,如果在通讯架构中,没有超时的设计,那么这个通讯架构就 ...