[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;
}

posted @ 2024-11-13 14:12  plus_cat  阅读(1)  评论(0编辑  收藏  举报