题目描述
某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检。他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不同的)
输入输出格式
输入格式:
只有一行且为用空格隔开的两个非负整数 n 和 m,其含义如上所述。 对于 30%的数据 n<=100,m<=100 对于 100%的数据 n<=2000,m<=2000
输出格式:
输出文件 output.txt 仅包含一个非负整数,表示不同的排法个数。注意答案可能很大。
输入输出样例
输入样例#1:
1 1
输出样例#1:
12
题解:高精+排列组合
n个男生排列A(n,n),然后插上两个老师A(n+1,2),然后插上m个女生
A(n+2,m-1),结果就是A(n,n)*A(n+1,2)*A(n+2,m-1)。
但是发现,两个老师插入时是可以挨在一起的,只要一个女生去他们中间就好了。
把两个老师看成一个男生,是A(n+1,n+1)*A(2,2),中间再插入一个女生
A(n+1,n+1)*A(2,2)*m,然后剩下的m-1个女生再插入,结果是
A(n+1,n+1)*A(2,2)*m*A(n+2,m-1)。
那么总的答案就是
A(n,n)*A(n+1,2)*A(n+3,m)+A(n+1,n+1)*A(2,2)*m+A(n+2,m-1)
化简一下式子最后只要高精乘就可以了。
这是个压位高精吧...背的Candy?模板我也不知道啊...(逃...
一直WA原来是数组开小了...
代码:
#include<iostream> #include<cstdio> #include<cstring> #define LL long long #define B 10000 using namespace std; LL m,n; struct Big{ int a[100020], n; int& operator [](int x) {return a[x];} Big():n(1) {memset(a, 0, sizeof(a));} void ini(int x) {a[1]=x; n=1;} }ans,p; Big operator *(Big a, int b) { int g=0; for(int i=1; i<=a.n; i++) g += a[i]*b, a[i] = g%B, g/=B; if(g) a[++a.n] = g; return a; } Big operator *(Big a, Big b) { Big c; for(int i=1; i<=a.n; i++) { int g=0; for(int j=1; j<=b.n; j++) g += c[i+j-1]+a[i]*b[j], c[i+j-1] = g%B, g/=B; c[i+b.n] = g; } c.n = a.n + b.n; while(c.n>1 && c[c.n]==0) c.n--; return c; } Big operator +(Big a, Big b) { int g=0, n=max(a.n, b.n); for(int i=1; i<=n; i++) { g += i<=a.n ? a[i] : 0; g += i<=b.n ? b[i] : 0; a[i] = g%B, g/=B; } a.n = n; if(g) a[++a.n] = g; return a; } Big operator -(Big a, Big b) { for(int i=1; i<=b.n; i++) { if(a[i]<b[i]) a[i]+=B, a[i+1]--; a[i] -= b[i]; } int p=b.n+1; while(a[p]<0) a[p]+=B, a[++p]--; while(a.n>1 && a[a.n]==0) a.n--; return a; } void Print(Big &a) { printf("%d", a[a.n]); for(int i=a.n-1; i>=1; i--) printf("%04d", a[i]); } int main(){ scanf("%d%d",&n,&m);ans.a[1]=1;p.a[1]=1; for(int i=2;i<=n;i++)ans=ans*i; ans=ans*n*(n+1); for(int i=n+3-m+1;i<=n+3;i++)ans=ans*i; for(int i=1;i<=n+1;i++)p=p*i; p=p*2*m; for(int i=n+3-m+1;i<=n+2;i++)p=p*i; ans=ans+p; Print(ans); return 0; }