传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2729
思路:简单的排列组合题
A(n,n)*(A(n+1,2)*A(n+3,m)+A(m,1)*A(2,2)*A(n+1,1)*A(n+2,m-1))
首先我们观察,男生无限制,先把男生排好即A(n,n)
然后我们排老师,老师不能相邻,n个男生有n+1个空位
如果老师被男生隔开,即有A(n+1,2)的方案
现在有了n+3个空位,还要放m个女生
即A(n+3,m)这就是式子加号前的部分
但是,在排女生前,老师可以相邻,只要我们后面用一个女生隔开
这样我们就有A(n,n)*A(2,2)*A(m,1)*A(n+2,m-1)种方案
即枚举两个老师的顺序,枚举中间的女生,最后有n+2个位置(两个老师捆在一起了)放剩下的m-1个女生
如果我们先排女生,再排老师,我们就会有很多种情况讨论
因为排完男生后,可以有两个女生相邻,可以有两组,每组两个女生相邻,还可以有三个女生相邻
最后再用两个老师把她们分开
什么,你说最后排男生?其实也可以做,只不过讨论起来比较复杂
答案很大,高精度即可
#include
#include
#include
#include
const int maxl=10010,P=10000;
using namespace std;
int n,m;
struct bign{
int v[maxl],len;
void del0(){while (len>1&&!v[len-1]) len--;}
void clear(){memset(v,0,sizeof(v)),len=1;}
bign operator *(const bign &b){
bign c;c.clear();
c.len=len+b.len;
for (int i=0;iP) c.v[i+j+1]+=c.v[i+j]/P,c.v[i+j]%=P;
}
c.del0();return c;
}
bign operator +(const bign &b){
bign c;c.clear();
c.len=max(len,b.len)+1;
for (int i=0;iP) c.v[i+1]++,c.v[i]-=P;
}
c.del0();return c;
}
void write(){
printf("%d",v[len-1]);
for (int i=len-2;i>=0;i--) printf("%04d",v[i]);
puts("");
}
};
bign fact(int a,int b){
bign res;res.clear();
if (a>b) return res;
res.v[0]=1;
for (int i=a;i<=b;i++){
bign pp;pp.clear(),pp.v[0]=i;
res=res*pp;
}
return res;
}
bign A(int n,int m){
if (!m){
bign res;res.clear(),res.v[0]=1;
return res;
}
if (m>n){bign res;res.clear();return res;}
return fact(n-m+1,n);
}
//A(n,n)*(A(n+1,2)*A(n+3,m)+A(m,1)*A(2,2)*A(n+1,1)*A(n+2,m-1))
int main(){
scanf("%d%d",&n,&m);
bign ans=A(n,n)*(A(n+1,2)*A(n+3,m)+A(m,1)*A(2,2)*A(n+1,1)*A(n+2,m-1));
ans.write();
return 0;
}