导航

洛谷P3223,HNOI2012 排队问题 题解

Posted on 2021-06-20 14:39  pipipapi  阅读(224)  评论(0)    收藏  举报

排队问题,插空法的变形

 

1.首先,如果只有两种人的话我们直接使用插空法就好了


对于n个男生和m个女生,如果要求女生之间不站在一起,首先让男生任意排列,在每个男生之间的空位(加上开头和结尾)一共n+1个位置中任意选取m个位置来让女生站队,最后在对女生进行任意排列

即,公式如下:
 
 
2.下面我们来看本题,多出来一个老师这个群体,要求是老师也不能相邻,因此我们需要想如何把三种群体转换为两种群体
 
思路来了:符合要求排列数==老师任意排列数-老师相邻排列数
 
我们应当将老师看作男同学的一种,不考虑老师本身个体的的差异化。带入上述公式符合要求排列数==老师任意排列数-老师相邻排列数
 
老师任意排列的数量:
 
老师相邻排列数(将老师们用绳子捆成一捆,看作一位男同学,这样子就能保证相邻了,只不过要注意捆在一起也有顺序,要×2):
 
因此答案的数量为
 
化简一下,用循环可以求解的形式表达出来就是:
 
注意!!别忘记写高精度!!!!
注意!!别忘记写高精度!!!!
注意!!别忘记写高精度!!!!
 

 

下面奉上代码:

 

//万能头文件
​#include<bits/stdc++.h>
using namespace std;
​
int ans[MAXN]={0};
int cnt=1;
//高精度乘法void multi(int x){
    for(int i=1;i<=cnt;i++){ 
​        ans[i]=x; 
​    } 
​    //进位 for(int i=1;i=10){
        ans[cnt+1]+=ans[cnt]/10,ans[cnt]%=10;
    cnt++;
    }
}

​int n,m;
//所有乘法操作void op(){
    multi(n*n+3n+2m);
    for(int i=1;i<=n+1;i++) 
​        multi(i); 
​    for(int i=n+4-m;i<=n+2;i++) 
​        multi(i); 
​} 
​
​int main(){ 
​    memset(ans,0,sizeof(ans)); 
​    ans[1]=1; 
​    scanf("%d %d",&n,&m); 
​    op(); 
​    //输出 for(int i=cnt;i>=1;i--){
    printf("%d",ans[i]);
    }
    return 0;
}