JZOJ6021. 【GDOI2019模拟2019.2.15】车

题意:

数据范围:

Analysis:

容斥无止境。
看到 m m m很小,方案很难算那肯定是容斥了。
先考虑 m = 0 m=0 m=0的情况:
我们考虑用总方案减去单独至少一条对角线上没有,再加上两条对角线上同时没有的方案。
因为是 n n n个车, n n n n n n列,那么每一列要放一个,且不能同行。
那么总方案显然是: n ! n! n!
考虑单独一条对角线:
我们考虑枚举放多少个在该条对角线上,容斥系数是 ( − 1 ) i (-1)^i (1)i
方案就是 ( i n ) ∗ ( n − i ) ! (^n_i)*(n-i)! (in)(ni)!。另一条对角线同理。
两条对角线同时没有:
我们枚举放多少个在第一条对角线上,放多少个在第二条对角线上。
那么容斥系数是 ( − 1 ) i + j (-1)^{i+j} (1)i+j,相当于在枚举放的位置的子集。
方案如何算?因为格子会互相影响,所以并不是简单地组合数。
我们发现互相影响的一定是 ( i , i ) , ( i , n − i + 1 ) , ( n − i + 1 , n − i + 1 ) , ( n − i + 1 , i ) (i,i),(i,n-i+1),(n-i+1,n-i+1),(n-i+1,i) (i,i),(i,ni+1),(ni+1,ni+1),(ni+1,i)这四个格子。
那么我们可以从最外层的矩形一层一层往内层 D P DP DP,设 f i f_i fi表示一共放 i i i个的方案。
然后每一层枚举选几个即可。
再考虑 m ! = 0 m!=0 m!=0的情况:
我们不妨再次容斥,考虑强制选其中一些位置,然后用上面的方法去解决。
然后对于情况分别讨论即可。
复杂度: O ( T ∗ n 2 ∗ 2 m ) O(T*n^2*2^m) O(Tn22m)

Code:

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 1e2 + 5;
const int mo = 1e4 + 7;
typedef long long ll;
int p[N][2],vis[N][2],C[N][N];
int f[N],g[N],fac[N];
int n,m,T,R;
inline int Z()
{
	int L = n,ret = 0;
	for (int i = 1 ; i <= n ; ++i) if (vis[i][0] || vis[i][1]) --L;
	for (int i = 0 ; i <= R ; ++i) ret = (ret + ((i & 1) ? -1 : 1) * (ll)C[L][i] * fac[R - i] % mo + mo) % mo;
	return ret;
}
inline int Y()
{
	int L = n,ret = 0;
	for (int i = 1 ; i <= n ; ++i) if (vis[i][0] || vis[n - i + 1][1]) --L;
	for (int i = 0 ; i <= R ; ++i) ret = (ret + ((i & 1) ? -1 : 1) * (ll)C[L][i] * fac[R - i] % mo + mo) % mo;
	return ret;
}
inline int A()
{
	int y = 0,e = 0,s = 0,ret = 0;
	for (int l = 1,r = n ; l <= r ; ++l,--r)
	{
		int fir = 2,sec = 2;
		if (l == r) --fir,--sec;
		if (vis[l][0]) --fir; if (vis[l][1]) --sec;
		if (!fir || !sec) continue;
		if (vis[r][0]) --fir; if (vis[r][1]) --sec;
		if (fir * sec == 1) ++y;
		else if (fir * sec == 2) ++e;
		else if (fir * sec == 4) ++s;
	} memset(f,0,sizeof(f)),f[0] = 1;
	for (int i = 1 ; i <= y ; ++i)
	{
		memset(g,0,sizeof(g));
		for (int j = 0 ; j <= R ; ++j) g[j] = (f[j] + (j ? f[j - 1] : 0)) % mo;
		memcpy(f,g,sizeof(f));
	}
	for (int i = 1 ; i <= e ; ++i)
	{
		memset(g,0,sizeof(g));
		for (int j = 0 ; j <= R ; ++j) g[j] = (f[j] + (j ? 2ll * f[j - 1] : 0)) % mo;
		memcpy(f,g,sizeof(f));
	}
	for (int i = 1 ; i <= s ; ++i)
	{
		memset(g,0,sizeof(g));
		for (int j = 0 ; j <= R ; ++j) g[j] = (f[j] + (j ? 4ll * f[j - 1] : 0) + (j > 1 ? 2ll * f[j - 2] : 0)) % mo;
		memcpy(f,g,sizeof(f));
	}
	for (int i = 0 ; i <= R ; ++i) ret = (ret + ((i & 1) ? -1 : 1) * (ll)f[i] * fac[R - i] % mo + mo) % mo;
	return ret;
}
int main()
{
//	freopen("a.in","r",stdin);
	freopen("rook.in","r",stdin);
	freopen("rook.out","w",stdout);
	scanf("%d",&T),fac[0] = C[0][0] = 1;
	while (T--)
	{
		scanf("%d%d",&n,&m); int lim = 1 << m,ans = 0;
		for (int i = 1 ; i <= m ; ++i) scanf("%d%d",&p[i][0],&p[i][1]),++p[i][0],++p[i][1];
		for (int i = 1 ; i <= n ; ++i)
		{
			fac[i] = (ll)fac[i - 1] * i % mo,C[i][0] = C[i][i] = 1;
			for (int j = 1 ; j < i ; ++j) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mo;
		}
		for (int i = 0 ; i < lim ; ++i)
		{
			bool pd = 0,fir = 0,sec = 0; memset(vis,0,sizeof(vis)),R = n;
			for (int j = 1 ; j <= m ; ++j)
			if (i & (1 << j - 1))
			{
				if (vis[p[j][0]][0]) { pd = 1; break; }
				if (vis[p[j][1]][1]) { pd = 1; break; }
				if (p[j][0] == p[j][1]) fir = 1;
				if (p[j][0] == n - p[j][1] + 1) sec = 1;
				vis[p[j][0]][0] = vis[p[j][1]][1] = 1,--R;
			} if (pd) continue;
			int X = (n - R) & 1 ? -1 : 1;
			if (fir && sec) ans = (ans + X * fac[R] + mo) % mo;
			else if (fir && !sec) ans = (ans + X * (fac[R] - Y()) + mo) % mo;
			else if (!fir && sec) ans = (ans + X * (fac[R] - Z()) + mo) % mo;
			else ans = (ans + X * ((ll)fac[R] - Z() - Y() + A()) + 2ll * mo) % mo;
		} printf("%d\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值