P10681 [COTS 2024] 奇偶矩阵 Tablica 题解
首先枚举行与列和为 \(1\) 或 \(2\) 的个数,我们设有 \(a\) 行和为 \(1\),\(b\) 行和为 \(2\),\(c\) 列和为 \(1\),\(d\) 列和为 \(2\)。显然它们满足下列关系:
所以只要有一个量确定了,其他三个也就定下来了。现在考虑对于固定的 \(a\),\(b\),\(c\),\(d\),我们可以将问题转化一下。这个问题相当于我们现在有 \(m\) 种颜色的小球,其中 \(c\) 种颜色有一个,其余 \(d\) 种有两个,我们现在需要把它们放入 \(n\) 个有标号集合中,其中有 \(a\) 个集合放一个球,其余 \(b\) 个集合放两个球,同一集合不能放入两个同色球。
接下来我们考虑把这 \(m\) 个小球按不同方式排列,对于每种方式我们都钦定前 \(a\) 个球每个球单独放入一个集合中,后面的我们将每相邻两个球放入同一个集合,但是这样可能会将两个同色球放入同一集合,所以我们对小球构成的序列还需要有限制,即后面 \(2b\) 的位置上每相邻两球颜色不同,也就是有 \(b\) 对小球颜色不能相同。这个限制很难描述,所以我们考虑容斥容斥掉了集合内出现同色球的方案。现在这 \(b\) 个集合每个集合交换两元素的位置其实一种方案但被统计了 \(2\) 次,所以每种方案都被重复统计了 \(2^b\) 次,最后还要乘 \(2^{-b}\)。
最后整理一下上面的每一步,就可以得到式子:
这个式子看着很长,但其实比较简单,建议自己先理解一下。拆开来讲的话就是,在 \(n\) 行中选 \(a\) 行和为 \(1\),在 \(m\) 列中选 \(c\) 列和为 \(1\)。后面要满足 \(b\)
组连续两个小球不同色,我们枚举有 \(t\) 组是同色的,再在 \(b\) 组里选 \(t\) 组,\(d\) 种颜色里选 \(t\) 种,这 \(t\) 组的顺序可以随意交换,其他 \(c+2d-2t\) 个小球位置任意,最后再乘上 \(2^{-b}\) 就可以了。
code:
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7,N=3e3+5;
ll fac[N<<1],invq[N<<1],n,m,ans,C[N][N];
ll qp(ll x,ll y)
{
ll res=1;
while(y)
{
if(y&1) (res*=x)%=mod;
(x*=x)%=mod,y>>=1;
}
return res;
}
inline ll rd()
{
char c;int f=1;
while(!isdigit(c=getchar()))if(c=='-') f=-1;
ll x=(c^48);
while(isdigit(c=getchar()))x=x*10+(c^48);
return x*f;
}
inline ll h(int i){return (i&1)?(mod-1):1;}
inline void add(ll &x,ll y){x+=y;if(x>=mod) x-=mod;}
inline ll solve(int a,int b,int c,int d)
{
ll res=0;
for(int t=0;t<=d&&t<=b;t++) add(res,h(t)*C[b][t]%mod*C[d][t]%mod*fac[t]%mod*fac[c+2*d-2*t]%mod*invq[d+b-t]%mod);
return res;
}
int main()
{
n=rd(),m=rd(),fac[0]=invq[0]=1;ll s=2*max(n,m),i2=qp(2,mod-2);
for(int i=1;i<=s;i++) fac[i]=fac[i-1]*i%mod,invq[i]=invq[i-1]*i2%mod;
for(int i=0;i<=max(n,m);i++)
{
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
for(int b=0;b<=n;b++)
{
int a=n-b,cnt=b*2+a;
if(cnt>=m&&cnt<=2*m) add(ans,C[n][b]*C[m][cnt-m]%mod*solve(a,b,2*m-cnt,cnt-m)%mod);
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号