bzoj2729: [HNOI2012]排队

来源:互联网 发布:inpaint去水印软件 编辑:程序博客网 时间:2024/05/22 10:22

传送门: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<cstdio>#include<cstring>#include<iostream>#include<algorithm>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;i<len;i++)for (int j=0;j<b.len;j++){c.v[i+j]+=v[i]*b.v[j];if (c.v[i+j]>P) 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;i<c.len;i++){c.v[i]+=v[i]+b.v[i];if (c.v[i]>P) 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;}


0 0
原创粉丝点击