题面
题解
拼命容斥即可。
先考虑 \(k=0\) 的情况。
首先先对对角线的限制容斥,即用 “没有限制-正对角线没选-反对角线没选+正反对角线都没选”。设 \(Z\) 中对角线不能选,设 \(Z\) 中对角线上的格子组成的集合为 \(P\)。
然后对行、列也用类似的方式容斥,设 \(X\) 中的行和 \(Y\) 中的列不能选,那么答案即为:
\[\sum(-1)^{|X|+|Y|+|Z|}\binom{\big|\{(i,j)|i\not\in X,j\not\in Y,(i,j)\not\in P\}\big|}{c} \]注意到 \(\big|\{(i,j)|i\not\in X,j\not\in Y,(i,j)\not\in P\}\big|\) 仅与 \(|X|,|Y|\) 和不在 \(X,Y\) 所包含的行列中却在 \(P\) 中的元素个数有关,不妨设不在 \(X,Y\) 中却在 \(P\) 中的元素个数为 \(t\),那么易得:
\[\big|\{(i,j)|i\not\in X,j\not\in Y,(i,j)\not\in P\}\big|=(n-|X|)(m-|Y|)-t \]所以我们考虑用 dp 来简化问题,而不是 \(2^{2n}\) 枚举行列的容斥:设 \(f_{i,x,y,t}\) 表示在前 \(i\) 行后 \(i\) 行前 \(i\) 列后 \(i\) 列中(即下图中的阴影部分),有 \(x\) 行不能选,有 \(y\) 列不能选,不在不能选的行和列中却在 \(P\) 中的格子数为 \(t\) 的方案数。
如图,当我们从 \(f_{i,x,y,t}\) 向 \(f_{i+1}\) 转移时,我们可以枚举第 \(i+1\) 行、第 \(n-i\) 行、 第 \(i+1\) 列、第 \(n-i\) 列选不选,然后计算出相应的 \(x',y',t'\),从 \(f_{i,x,y,t}\) 向 \(f_{i+1,x',y',t'}\) 转移即可。
时间复杂度 \(O(n^4)\)。(省略了许多常数)
当 \(k>0\) 时,我们同样容斥,钦定某若干个格子必须选,那么它们所在的行和列都必须选,容斥时判断一下即可。
代码如下:
#include<bits/stdc++.h>
#define N 35
using namespace std;
namespace modular
{
const int mod=10007;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void Add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
inline void Dec(int &x,int y){x=x-y<0?x-y+mod:x-y;}
inline void Mul(int &x,int y){x=1ll*x*y%mod;}
}using namespace modular;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
struct Point
{
int x,y;
}p[10];
int n1[130],C[N*N][N*N];
int n,k,c;
int dp[2][N][N][N<<1];
bool cx[N],cy[N];
void init()
{
for(int i=1;i<128;i++) n1[i]=n1[i>>1]+(i&1);
C[0][0]=1;
for(int i=1;i<=n*n;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=add(C[i-1][j-1],C[i-1][j]);
}
}
int work2(bool bd0,bool bd1,int cnum)
{
int nbd=bd0+bd1;
int now=0;
memset(dp[now],0,sizeof(dp[now]));
dp[now][0][0][0]=1;
for(int i=1,j=n;i<j;i++,j--)
{
int nxt=now^1;
memset(dp[nxt],0,sizeof(dp[nxt]));
for(int brow=0;brow<=(i-1)*2;brow++)
{
for(int bline=0;bline<=(i-1)*2;bline++)
{
for(int bd=0;bd<=(i-1)*2*nbd;bd++)
{
if(!dp[now][brow][bline][bd]) continue;
for(int u=0;u<2;u++)
{
if(u&&cx[i]) continue;
for(int d=0;d<2;d++)
{
if(d&&cx[j]) continue;
for(int l=0;l<2;l++)
{
if(l&&cy[i]) continue;
for(int r=0;r<2;r++)
{
if(r&&cy[j]) continue;
int tmp=0;
if(bd0) tmp+=((!u)&&(!l))+((!d)&&(!r));
if(bd1) tmp+=((!u)&&(!r))+((!d)&&(!l));
Add(dp[nxt][brow+u+d][bline+l+r][bd+tmp],dp[now][brow][bline][bd]);
}
}
}
}
}
}
}
now=nxt;
}
if(n&1)
{
int i=(n+1)/2;
int nxt=now^1;
memset(dp[nxt],0,sizeof(dp[nxt]));
for(int brow=0;brow<=n-1;brow++)
{
for(int bline=0;bline<=n-1;bline++)
{
for(int bd=0;bd<=(n-1)*nbd;bd++)
{
if(!dp[now][brow][bline][bd]) continue;
for(int u=0;u<2;u++)
{
if(u&&cx[i]) continue;
for(int l=0;l<2;l++)
{
if(l&&cy[i]) continue;
int tmp=((bd0||bd1)&&((!u)&&(!l)));
Add(dp[nxt][brow+u][bline+l][bd+tmp],dp[now][brow][bline][bd]);
}
}
}
}
}
now=nxt;
}
int ans=0;
for(int brow=0;brow<=n;brow++)
{
for(int bline=0;bline<=n;bline++)
{
for(int bd=0;bd<=n*nbd-((n&1)&&(nbd==2));bd++)
{
if(!dp[now][brow][bline][bd]) continue;
int able=(n-brow)*(n-bline)-bd;
if(able<c) continue;
int tmp=mul(C[able-cnum][c-cnum],dp[now][brow][bline][bd]);
if((brow+bline)&1) Dec(ans,tmp);
else Add(ans,tmp);
}
}
}
return ans;
}
int work1(int csta)
{
memset(cx,0,sizeof(cx));
memset(cy,0,sizeof(cy));
bool cd0=0,cd1=0;
for(int i=1;i<=k;i++)
{
if((csta>>(i-1))&1)
{
cx[p[i].x]=cy[p[i].y]=1;
if(p[i].x==p[i].y) cd0=1;
if(p[i].x+p[i].y==n+1) cd1=1;
}
}
int ans=0;
for(int bd0=0;bd0<2;bd0++)
{
if(bd0&&cd0) continue;
for(int bd1=0;bd1<2;bd1++)
{
if(bd1&&cd1) continue;
if((bd0+bd1)&1) Dec(ans,work2(bd0,bd1,n1[csta]));
else Add(ans,work2(bd0,bd1,n1[csta]));
}
}
return ans;
}
int main()
{
n=read(),k=read(),c=read();
init();
for(int i=1;i<=k;i++) p[i].x=read(),p[i].y=read();
int ans=0;
for(int csta=0;csta<(1<<k);csta++)
{
if(n1[csta]&1) Dec(ans,work1(csta));
else Add(ans,work1(csta));
}
printf("%d\n",ans);
return 0;
}
/*
3 1 4
1 2
*/
/*
16 2 18
1 3
5 7
*/
标签:XSY3997,int,big,容斥,ch,对角线,dp,mod
From: https://www.cnblogs.com/ez-lcw/p/16842960.html