bzoj 2729: [HNOI2012]排队

Description

某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检。他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不同的)

Solution

写复杂了
可以先摆好 \(n\) 个男同学,再把女同学和老师分别插空,保证不相邻
发现女生实际是可以先相邻然后再插老师的,所以讨论老师的摆法
设老师为\(T\),女生为\(G\),有 \(GTG\),\(GTGTG\) 两种,分别把这个整体当作女生计算一下即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4010,mod=1e5;
int n,m,prime[N],pre[N],num=0,cnt[N];
void priwork(){
	for(int i=2;i<=n+m+2;i++){
		if(!pre[i])prime[++num]=i,pre[i]=i;
		for(int j=1;j<=num && i*prime[j]<=n+m+2;j++){
			pre[i*prime[j]]=prime[j];
			if(i%prime[j]==0)break;
		}
	}
}
inline void add(int x){
	if(!x)cnt[0]++;
	while(x>1){
		cnt[pre[x]]++;
		x/=pre[x];
	}
}
struct sub{
	int len,a[N];
	sub(){memset(a,0,sizeof(a));len=0;}
	inline void init(){len=0;memset(a,0,sizeof(a));a[++len]=1;}
	inline void operator *=(const int &t){
		for(int i=1;i<=len;i++)a[i]*=t;
		for(int i=1;i<=len;i++)
			if(a[i]>=mod)a[i+1]+=a[i]/mod,a[i]%=mod;
		while(a[len+1]){
			len++;
			if(a[len]>=mod)a[len+1]+=a[len]/mod,a[len]%=mod;
		}
	}
	inline void operator +=(const sub &t){
		len=max(len,t.len);
		for(int i=1;i<=len;i++){
			a[i]+=t.a[i];
			if(a[i]>=mod)a[i]-=mod,a[i+1]++;
		}
		while(a[len+1]){
			len++;
			if(a[len]>=mod)a[len+1]++,a[len]-=mod;
		}
	}
	inline void Print(){
		printf("%d",a[len]);
		for(int i=len-1;i>=1;i--)
			for(int j=mod/10;j;j/=10)
				printf("%d",a[i]/j),a[i]%=j;
		puts("");
	}
};
int main(){
	freopen("pp.in","r",stdin);
	freopen("pp.out","w",stdout);
	cin>>n>>m;
	priwork();
	for(int i=n-m+2;i<=n+1;i++)add(i);
	for(int i=1;i<=n;i++)add(i);
	add(n+m);add(n+m+1);
	sub ans,t;
	t.init();
	for(int i=0;i<=n+m+2;i++)
		for(int j=1;j<=cnt[i];j++)t*=i;
	ans+=t;
	memset(cnt,0,sizeof(cnt));t.init();
	for(int i=1;i<=n;i++)add(i);
	for(int i=n-m+3;i<=n+1;i++)add(i);
	add(m);add(m-1);add(n+m);add(2);
	for(int i=0;i<=n+m+2;i++)
		for(int j=1;j<=cnt[i];j++)t*=i;
	ans+=t;
	memset(cnt,0,sizeof(cnt));t.init();
	for(int i=1;i<=n;i++)add(i);
	for(int i=n-m+4;i<=n+1;i++)add(i);
	add(m);add(m-1);add(m-2);add(m-1);
	for(int i=0;i<=n+m+2;i++)
		for(int j=1;j<=cnt[i];j++)
			t*=i;
	ans+=t;
	ans.Print();
	return 0;
}

posted @ 2018-02-23 16:36  PIPIBoss  阅读(132)  评论(0编辑  收藏  举报