JZOJ 3059. 【NOIP2012模拟10.26】雕塑

版权声明:喜欢请点个大拇指,感谢各位dalao。弱弱说下,转载要出处呦 https://blog.csdn.net/qq_35786326/article/details/85856999


分析:

总方案数显然是 n ! n!
但是题目中有障碍物,所以我们考虑用总方案数-障碍物的方案数
但随后我们发现,答案貌似不太对!——因为我们计算了重复的部分。所以我们就使用容斥原理解决


代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#include<deque>
#include<set>
#define LL long long
using namespace std;
inline LL read(){
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
int n,m,q,r[50],a[50][5],h[50],s[50];
LL d[50],ans;
void dfs(int o,int t){
	if(!t){
		r[q]++;return;
	}
	for(int i=o+1;i<=m;++i)
	if(!h[a[i][1]]&&!s[a[i][2]])
	{
		h[a[i][1]]=1;s[a[i][2]]=1;
		dfs(i,t-1);
		h[a[i][1]]=0;s[a[i][2]]=0;
	}
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=m;++i) a[i][1]=read(),a[i][2]=read();
	for(q=1;q<=m;++q) dfs(0,q);
	d[1]=1;d[0]=1;
	for(int i=2;i<=n;++i) d[i]=d[i-1]*i;
	ans=1;
	for(int i=2;i<=n;++i) ans*=i;
	for(int i=1;i<=m;++i)
	  if(i%2==1) ans-=r[i]*d[n-i];
	  else ans+=r[i]*d[n-i];
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35786326/article/details/85856999