Description
笨笨当了很久的道路调度员,笨笨也开始想体验生活,从生活中发现数学问题,锻炼自己思维。最近《变形金刚3》,《哈利波特7》同步放映,明显是决战雌雄,已知王府井中一共有n人买了《变形金刚3》的票,m人买了《哈利波特7》的票,并且n>=m,并且电影院中现在只有两种票,每次只有一个人买,(共有n+m次),这n+m次组成一个排列,为了保证每一个人买票时,《变形金刚3》票房都不少于《哈利波特7》,(n个买《变形金刚3》的人之间没区别,m个买《哈利波特7》的人也没区别),笨笨想着到这样的购票方案有多少种。笨笨想了好久都没想出来,所以笨笨找到了你。
Input
一行两个数n,m ( 0<=m<=n<=5000)
Output
输出方案种数
Hint
0<=m<=n<=5000
Analysis
类似的题目做过,购票问题
0分做法:
dfs爆搜可能性,优化剪枝一下可能拿10分+
0分做法:
经典的dp,设
f[i][j]
表示前
i
人有
当
j∗2≥i
时
f[i][j]+=f[i−1][j]
第
i
人买《哈利波特7》
注意需要高精度,考虑到时间复杂度为
正解:
假设将买《变形金刚3》票的人记为s,买《哈利波特7》的人记为x。
则n个买《变形金刚3》的与m个买《哈利波特7》的人的队伍就可以用一个具有n个s和m个x的字符串,显然这样的字符串共有C(n+m,n)个
其中不满足问题要求的串一定存在一个最靠左的位置p,使得从第一个字符到第p个字符为止的子串中x的个数比s的个数大1。
如sxsxx…就是一个不满足条件的串,其中p=5。
我们将从头到p为止的子串中的字符s换成x则得到一个具有n+1个s,m-1个x的串。
可以证明这种转换是一一对应的,即任意一个n+1个s,m-1个x的串都可以按照逆规则转换成一个不满足题目条件的串.
转换规则为在任意一个n+1个s,m-1个x中找到最靠左的p,使得从头到p的子串中s的个数比x个数大1,将到p为止的子串中的s与x互换则得到n个s和m个x的串.
且此串一定不能满足条件,而具有n+1个s,m-1个x的串只有C(n+m,n+1)
那么ans=C(n+m,n)-C(n+m,n+1)
本段文字转自某媳妇
计算的时候要高精度压位,c++大数打起来很累但用着爽
Code
#include <stdio.h>
#include <cstring>
#define mod 10000
#define maxn 1000
using namespace std;
struct num
{
int s[maxn+1];
__attribute__((optimize("O2")))
inline num operator *(int x)
{
num c={0};int v=0;
for (int i=maxn;i>0;i--)
{
c.s[i]=s[i]*x+v;
v=c.s[i]/mod;
c.s[i]%=mod;
}
return c;
}
__attribute__((optimize("O2")))
inline num operator /(int x)
{
num c={0};int v=0;
for (int i=1;i<=maxn;i++)
{
int t=v*mod+s[i];
c.s[i]=t/x;
v=t%x;
}
return c;
}
__attribute__((optimize("O2")))
inline num operator -(num b)
{
num c={0};int v=0;
for (int i=maxn;i>0;i--)
{
if (s[i]-v>=b.s[i])
c.s[i]=s[i]-b.s[i]-v,v=0;
else
c.s[i]=s[i]-b.s[i]-v+mod,v=1;
}
return c;
}
__attribute__((optimize("O2")))
inline void output()
{
int i=1;
while (!s[i])
i++;
printf("%d",s[i]);
for (int j=i+1;j<=maxn;j++)
{
int p=4,f[5];
memset(f,0,sizeof(f));
do{
f[p--]=s[j]%10;
}while (s[j]/=10);
for (int k=1;k<=4;k++)
printf("%d",f[k]);
}
printf("\n");
}
};
int main()
{
int n,m;
num a,b,ans;
memset(a.s,0,sizeof(a.s));
memset(b.s,0,sizeof(b.s));
memset(ans.s,0,sizeof(ans.s));
a.s[maxn]=b.s[maxn]=1;
scanf("%d%d",&n,&m);
int i,j;
for (i=1,j=m+n;i<m;i++,j--)
b=b*j,b=b/i;
a=b*j,a=a/i;
ans=a-b;
ans.output();
return 0;
}