CF2150B Grid Counting 题解
手玩发现条件二和条件三中的条件,等价于如下图所示的每一个块里面恰好出现一个黑色元素。

然后因为\((1,1)\)和\((1,n)\)这个格子必选,所以说我们可以推出来\((2,1),(3,1),...,(n,1),(n,2),(n,3),...,(n,n),(n-1,n),(n-2,n),...,(3,n),(2,n),(1,n)\)这些格子不能填了,因为条件二和条件三的存在。
然后再考虑第\(2\)列和第\(n-1\)列,这两列只有第一行和第二行能涂黑,因为需要满足如上图所示的每个块里面恰好出现一个黑色元素。涂黑之后,那么他们下侧的格子也不能涂黑了,如下图所示。

以此类推,第\(1,n\)列只有上面第一行可涂黑,第\(2,n-1\)列只有上面第一行,第二行可涂黑,第\(3,n-2\)列只有上面第第一行,第二行,第三行可涂黑。
那么也就是说我们需要在可以涂黑的里面选出n个格子涂黑。我们可以从第\(n\)行向第\(1\)行遍历,记录每次可选的格子\(c\),如果是\(n\)为奇数,那么在第\(\lfloor \frac{n}{2} \rfloor +1\)行\(+1\)。当在第\(\lfloor \frac{n}{2} \rfloor\)及其以下的时候,我们每次可选的格子\(+2\),如果当前的\(a_i>c\),说明需要选的格子已经超过了我们能选的格子,所以说这个时候无解,如果到第一行的时候\(a_1 \ne c\),那么也是无解,说明需要选的格子不是\(n\)个。
代码
#include <bits/stdc++.h>
using namespace std;
/*
*/
#define ll long long
const ll mod=998244353;
const int N=2e5+2;
ll fac[N],inv[N];
ll ksm(ll a,ll b,ll mod){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod,b>>=1;
}
return res;
}
void init(){
fac[0]=1;
for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%mod;
inv[N-1]=ksm(fac[N-1],mod-2,mod);
for(int i=N-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(ll n,ll m){
if(n<m||n<0||m<0) return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
void sol() {
ll n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
ll c=0,ans=1;
for(int i=n;i>=1;i--){
// cout<<i<<" "<<c<<'\n';
if((n&1)&&i==n/2+1) c++;
if(i<=n/2) c+=2;
if(i==1&&c!=a[i]){
cout<<"0\n";
return ;
}else if(a[i]>c){
cout<<"0\n";
return ;
}else{
ans=ans*C(c,a[i])%mod;
c-=a[i];
}
}
cout<<ans<<'\n';
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
init();
int t = 1;
cin >> t;
while (t--) {
sol();
}
return 0;
}
总结:正难则反,正向思考解决方案不好做的时候尝试倒序解决

浙公网安备 33010602011771号