[NOIP2022] 种花 题解
[NOIP2022] 种花 题解
知识点
枚举、前缀和。
题意简述
分别求给出的二维网格图中不经过障碍的连成 “C” 形和 ”F“ 形的方案数。
分析
固定横坐标,纵坐标后缀累加无障碍最远的地方,作为 “C” 和 “F” 的两横。
然后固定纵坐标,横坐标前缀累加求无障碍最远值的和,作为 “C” 和 “F” 的上面一横。
枚举下面那一横的开端的横纵坐标,乘上上面一横的和,就得到了 “C” 的方案数。
然后再把 “C” 的方案数累加,枚举 “F” 最下面点的坐标,即可求出 “F” 的方案数。
代码
时空复杂度:\(O(nm)\)。
#define Plus_Cat "plant"
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i((g).h[x]),y((g)[i].v);~i;y=(g)[i=(g)[i].nxt].v)
using namespace std;
constexpr int N(1e3+10);
namespace Modular {
#define Mod 998244353
template<class T1,class T2>constexpr auto add(const T1 a,const T2 b) {
return a+b>=Mod?a+b-Mod:a+b;
}
template<class T1,class T2>T1 &toadd(T1 &a,const T2 b) {
return a=add(a,b);
}
template<class T1,class T2>constexpr auto mul(const T1 a,const T2 b) {
return (ll)a*b%Mod;
}
template<class T1,class T2>T1 &tomul(T1 &a,const T2 b) {
return a=mul(a,b);
}
} using namespace Modular;
char s[N][N];
int Cas,ID,n,m,C,F,ansC,ansF;
int suf[N][N],pre[N][N],cnt[N][N];
namespace Subtask1 {
bool Check() {
return n<=500&&m<=500;
}
int Cmain() {
FOR(i,1,n) {
suf[i][m+1]=0;
DOR(j,m,1)if(s[i][j]=='0')suf[i][j]=add(suf[i][j+1],1);
}
FOR(j,1,m)FOR(l,1,n)if(s[l][j]=='0'&&s[l+1][j]=='0')FOR(r,l+2,n) {
if(s[r][j]=='1')break;
toadd(cnt[r][j],mul(suf[l][j]-1,suf[r][j]-1));
}
FOR(i,1,n)FOR(j,1,m)toadd(ansC,cnt[i][j]);
FOR(j,1,m)FOR(r,1,n)if(s[r][j]=='0')DOR(l,r-1,1) {
if(s[l][j]=='1')break;
toadd(ansF,cnt[l][j]);
}
printf("%d %d\n",C?ansC:0,F?ansF:0);
return 0;
}
}
namespace Subtask {
int Cmain() {
FOR(i,1,n) {
suf[i][m+1]=0;
DOR(j,m,1)if(s[i][j]=='0')suf[i][j]=add(suf[i][j+1],1);
}
FOR(j,1,m) {
pre[0][j]=0;
FOR(i,1,n)if(s[i][j]=='0')pre[i][j]=add(pre[i-1][j],suf[i][j]-1);
}
FOR(j,1,m)FOR(i,3,n)if(s[i][j]=='0'&&s[i-1][j]=='0'&&s[i-2][j]=='0')
cnt[i][j]=mul(suf[i][j]-1,pre[i-2][j]),toadd(ansC,cnt[i][j]);
FOR(j,1,m) {
cnt[0][j]=0;
FOR(i,1,n)if(s[i][j]=='0')toadd(cnt[i][j],cnt[i-1][j]);
}
FOR(j,1,m)FOR(i,4,n)if(s[i][j]=='0'&&s[i-1][j]=='0')toadd(ansF,cnt[i-1][j]);
printf("%d %d\n",C?ansC:0,F?ansF:0);
return 0;
}
}
int Cmain() {
scanf("%d%d%d%d",&n,&m,&C,&F),ansC=ansF=0,RCL(suf,0,suf,1),RCL(pre,0,pre,1),RCL(cnt,0,cnt,1);
FOR(i,1,n)scanf("%s",s[i]+1);
if(Subtask1::Check())return Subtask1::Cmain();
return Subtask::Cmain();
}
int main() {
#ifdef Plus_Cat
freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
for(scanf("%d%d",&Cas,&ID);Cas;--Cas)Cmain();
return 0;
}