题解:「NOIP2022 提高组」种花

题解:「NOIP2022 提高组」种花

题目大意:给定一个 \(n \times m\) 的01矩阵,0表示可以种花,1表示土坑(无法种花),现在要在图上种出一个C型或F型(C,F横着的两条线的长度都可以不同,但一定是面向右边的),现在问你种C和F分别有多少种方案(除了这个形状外不能在任何地方种花),多组数据,\(T \leq 5\)。 答案对998244353取模 。

原题面中对形状的定义是这样的:

一种种花方案被称为 \(\texttt{C-}\) 的,如果存在 \(x_1, x_2 \in [1, n]\),以及 \(y_0, y_1, y_2 \in [1, m]\),满足 \(x_1 + 1 < x_2\),并且 \(y_0 < y_1, y_2 \leq m\),使得第 \(x_1\) 的第 \(y_0\) 到第 \(y_1\) 、第 \(x_2\) 的第 \(y_0\) 到第 \(y_2\) 以及第 \(y_0\) 的第 \(x_1\) 到第 \(x_2\) 不为土坑,且只在上述这些位置上种花。

一种种花方案被称为 \(\texttt{F-}\) 的,如果存在 \(x_1, x_2, x_3 \in [1, n]\),以及 \(y_0, y_1, y_2 \in [1, m]\),满足 \(x_1 + 1 < x_2 < x_3\),并且 \(y_0 < y_1, y_2 \leq m\),使得第 \(x_1\) 的第 \(y_0\) 到第 \(y_1\) 、第 \(x_2\) 的第 \(y_0\) 到第 \(y_2\) 以及第 \(y_0\) 的第 \(x_1\) 到第 \(x_3\) 不为土坑,且只在上述这些位置上种花。

\(Subtask: n \leq 500\)

先考虑C形,发现当两横线位置固定时,竖线位置是固定的。所以只需关心横线对答案的贡献

横线对答案的贡献等于两横线长度之积,怎么快速求出每个点往右能延伸的最大长度呢?每一行从右往左做后缀和即可,预处理可以在 \(O(N^2)\) 内完成

考虑 \(O(N^3)\) 统计答案:

第一层循环枚举列数 \(j\)

第二层枚举上方横线所在行号 \(i\)

第三层枚举下方横线所在行号 \(k\)

\(r_{i,j}\) 表示点 \((i,j)\) 能向右延伸的最大长度,则有

\[ansc=\sum_{j=1}^{m}\sum_{i=1}^{n}\sum_{k=i+2}^{n}(r_{i,j}-1) \times (r_{k,j}-1) \]

那F形呢?发现就是在C的基础上在竖线下方加一截。

\(c_{i,j}\) 表示 \((i,j)\) 能向下延伸的最大长度,同样可以预处理后缀和,则有

\[ansc=\sum_{j=1}^{m}\sum_{i=1}^{n}\sum_{k=i+2}^{n}(r_{i,j}-1) \times (r_{k,j}-1) \times (c_{k,j}-1) \]

时间复杂度 \(O(TN^3)\) ,加上输出0的特判,期望得分67pts,但好像CCF数据太水,T根本没有5,所以实际得分75pts。

正解: $ n \leq 1000$

考虑怎么优化到 \(O(N^2)\) 或者 \(O(N^2logN)\)

发现固定 \(i,j\) 后, 涉及\(k\) 的部分可以进一步处理成前缀和。

所以记 \(sr_{i,j}\) 表示 \(\sum_{k=i}^{n} r_{k,j}-1\)\(ssr_{i,j}\) 表示 \(\sum_{k=i}^{n} (r_{k,j}-1) \times (c_{k,j}-1)\)

注意做的也是后缀和而不是前缀

然后就只需要枚举 \(i,j\) 即可,时间复杂度 \(O(N^2)\) , 期望得分100pts

#include<bits/stdc++.h>
#define F(i,l,r) for(int i=l;i<=r;++i)
#define G(i,r,l) for(int i=r;i>=l;--i)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
const int N=1010;
const ll mod=998244353;
int n,m,vc,vf,t,id;
char ch[N][N];
ll ansf,ansc,r[N][N],c[N][N],sr[N][N],ssr[N][N];
int main(){
//	freopen("plant.in","r",stdin);
//	freopen("plant.out","w",stdout);
	scanf("%d%d",&t,&id); 
	while(t--){
		ansf=0,ansc=0,mem(r),mem(c),mem(sr),mem(ssr),mem(ch);
		scanf("%d%d%d%d",&n,&m,&vc,&vf);
		F(i,1,n) scanf("%s",ch[i]+1);
		if(!vc && !vf){ puts("0 0"); continue; }
		F(i,1,n) G(j,m,1) ch[i][j]=='1'?r[i][j]=0:r[i][j]=r[i][j+1]+1;
		F(j,1,m) G(i,n,1) ch[i][j]=='1'?c[i][j]=0:c[i][j]=c[i+1][j]+1;
		F(j,1,m) G(i,n,1) {
			if(ch[i][j]=='1') continue;
			sr[i][j]=r[i][j]-1,ssr[i][j]=(r[i][j]-1)*(c[i][j]-1)%mod;
			if(ch[i+1][j]=='0' && i+1<=n) sr[i][j]=(sr[i][j]+sr[i+1][j])%mod,ssr[i][j]=(ssr[i][j]+ssr[i+1][j])%mod;
		}
		F(j,1,m){
			F(i,1,n-2){
				if(r[i][j]<=1 || ch[i+1][j]=='1' || ch[i+2][j]=='1') continue;
				ansc=(ansc+(r[i][j]-1)*sr[i+2][j]%mod)%mod;
				ansf=(ansf+(r[i][j]-1)*ssr[i+2][j]%mod)%mod;
			}
		}
		printf("%lld %lld\n",vc?ansc:0,vf?ansf:0);
	}
	return 0;
}
posted @ 2023-10-29 18:49  superl61  阅读(84)  评论(0编辑  收藏  举报