Description
求从(0,0)点走到(n,m)点不越过直线y=x的方案数。
n,m<=5000
Solution
首先,这是一个经典问题,相信大家都会做。
正难则反,我们用总数减去不合法的方案数。
总数很明显是
Cmm+n
然后,因为题目要求是不越过,我们把直线向上平移一格,变成y=x+1,
然后作出原点关于这条直线的对称点(-1,1),那么不和法的方案数就是
Cm−1m+n
不过这道题没有要求取模%%%
于是就要上高精度了。。。
不过,我们可以把上下分解质因数(其实也不用),然后再一一抵消掉,就不用写高精除了。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define N 10000
using namespace std;
const int maxn=100000;
struct num{
int shu[N];
friend num operator-(num y,num z) {
num x;memset(x.shu,0,sizeof(x.shu));x.shu[0]=y.shu[0];
fo(i,1,x.shu[0]) {
x.shu[i]+=y.shu[i]-z.shu[i];
if (x.shu[i]<0) x.shu[i]+=maxn,x.shu[i+1]--;
}
while (!x.shu[x.shu[0]]) x.shu[0]--;
return x;
}
friend num operator*(num y,int z) {
num x;memset(x.shu,0,sizeof(x.shu));x.shu[0]=y.shu[0];
fo(i,1,x.shu[0]) {
x.shu[i]+=y.shu[i]*z;
x.shu[i+1]+=x.shu[i]/maxn;
x.shu[i]%=maxn;
}
while (x.shu[x.shu[0]+1]) x.shu[0]++;
return x;
}
}ans;
int p[N+5],c[N+5],n,m;
void recout(int x,int f) {
for(;x!=1;x/=p[x]) c[p[x]]+=f;
}
num C(int m,int n) {
num x;memset(x.shu,0,sizeof(x.shu));
x.shu[0]=x.shu[1]=1;
memset(c,0,sizeof(c));
fo(i,n+1,m) recout(i,1);
fo(i,1,m-n) recout(i,-1);
fo(i,1,N) fo(j,1,c[i]) x=x*i;
return x;
}
int main() {
fo(i,2,N) if (!p[i]) fo(j,1,N/i) p[i*j]=i;
scanf("%d%d",&n,&m);
ans=C(m+n,m)-C(m+n,m-1);
printf("%d",ans.shu[ans.shu[0]]);
fd(i,ans.shu[0]-1,1) printf("%05d",ans.shu[i]);
}