首页 > 其他分享 >【题解】P8865 [NOIP2022] 种花

【题解】P8865 [NOIP2022] 种花

时间:2024-12-08 13:43:26浏览次数:4  
标签:后缀 int 题解 复杂度 lst -- P8865 NOIP2022 mathcal

题目传送门

题目大意

有一个 \(n\times m\) 的花园,\(a_{i,j}=1\) 表示可以种花,\(a_{i,j}=0\) 表示不可以种花,请求出有多少种种花的的方案,使得形成 CF 的形状,\(n,m\le 10^3\)。

思路分析

观察 CF,发现 F 可以认为是 C 的左下角加一笔竖画,所以先求 C

求形成 C 的方案数

image-20241208130114793

枚举 C 的左上角的点和左下角的点,即枚举第 \(j\) 列,黄色点在这一列的第 \(x\) 行,蓝色点在这一列的第 \(y\) 行,然后计算一下黄色点能往右延伸几格,蓝色点能往右延伸几格,相乘即可。这一步可以用后缀和 \(r_{i,j}\) 来实现。

for(int i=1;i<=n;i++){
	for(int j=m;j>=1;j--){
		if(a[i][j]=='1'){
			r[i][j]=0;
           }else{
			r[i][j]=r[i][j+1]+1;
		}
	}
}
for(int j=1;j<=m;j++){
    for(int x=1;x<=n;x++){
        for(int y=x+2;y<=n;y++){
            if(a[x][j]=='1'){
                break;
            }
            ansc=ansc+(r[x][j]-1)*(r[y][j]-1);
        }
    }
}

计算时 \((r_{x,j}-1)\times(r_{y,j}-1)\) 不好看,所以预处理后缀和后非 \(0\) 的 \(r_{i,j}\) 都减去 \(1\) 就行了。

for(int i=1;i<=n;i++){
	for(int j=m;j>=1;j--){
		if(a[i][j]=='1'){
			r[i][j]=0;
           }else{
			r[i][j]=r[i][j+1]+1;
		}
	}
}
for(int i=1;i<=n;i++){
	for(int j=m;j>=1;j--){
		if(r[i][j]!=0){
			r[i][j]--;
		}
	}
}
for(int j=1;j<=m;j++){
    for(int x=1;x<=n;x++){
        for(int y=x+2;y<=n;y++){
            if(a[x][j]=='1'){
                break;
            }
            ansc=ansc+r[x][j]*r[y][j];
        }
    }
}

后缀和时间复杂度为 \(\mathcal{O(nm)}\),计算的时间复杂度为 \(\mathcal{O(n^2m)}\),代码的时间复杂度为 \(\mathcal{O(n^2m)}\),超时。

继续观察计算的三重循环,发现计算时只有 \(r_{y,j}\) 发生变化,可以再用一个后缀和维护后缀和 \(r_{i,j}\),记为 \(suf_{i,j}\),省去第三重循环 \(y\)。

for(int i=n;i>=1;i--){
	for(int j=1;j<=m;j++){
		suf[i][j]=suf[i+1][j]+r[i][j];
	}
}
for(int j=1;j<=m;j++){
	int lst=n+1;
	for(int x=n;x>=1;x--){
		if(a[x][i]=='1'){
			lst=x;
			continue;
		}
		if(lst<x+2){
			continue;
		}
		ansc=ansc+(suf[x+2][i]-suf[lst][i])*r[x][i];
	}
}

这样,时间复杂度降为 \(\mathcal{O(nm)}\),不超时。

求形成 C 的方案数

image-20241208132347351

C 类似,同样先枚举 F 的左上角的点和第二条杠左边的点,即枚举第 \(j\) 列,黄色点在这一列的第 \(x\) 行,蓝色点在这一列的第 \(y\) 行,然后计算一下黄色点能往右延伸几格,蓝色点能往右延伸几格,还计算蓝色点能向下延伸格,相乘即可。向右和 C 的后缀和 \(r_{i,j}\) 相同,向下再用后缀和数组 \(d_{i,j}\) 实现。

for(int i=n;i>=1;i--){
	for(int j=1;j<=m;j++){
		if(a[i][j]=='1'){
			d[i][j]=0;
		}else{
			d[i][j]=d[i+1][j]+1;
		}
	}
}
for(int i=n;i>=1;i--){
	for(int j=1;j<=m;j++){
		if(d[i][j]!=0){
			d[i][j]--;
		}
	}
}
for(int j=1;j<=m;j++){
    for(int x=1;x<=n;x++){
        for(int y=x+2;y<=n;y++){
            if(a[x][j]=='1'){
                break;
            }
            ansf=ansf+r[x][j]*r[y][j]*d[y][j];
        }
    }
}

后缀和时间复杂度为 \(\mathcal{O(nm)}\),计算的时间复杂度为 \(\mathcal{O(n^2m)}\),代码的时间复杂度为 \(\mathcal{O(n^2m)}\),超时。

计算时有 \(r_{y,j}\times d_{y,j}\) 发生变化,可以再用一个后缀和维护 \(r_{i,j}\times d_{y,j}\),记为大 \(Suf_{i,j}\),省去第三重循环 \(y\)。

for(int i=n;i>=1;i--){
	for(int j=1;j<=m;j++){
		Suf[i][j]=Suf[i+1][j]+r[i][j]*d[i][j];
	}
}
for(int i=1;i<=m;i++){
	int lst=n+1;
	for(int x=n;x>=1;x--){
		if(a[x][i]=='1'){
			lst=x;
			continue;
		}
		if(lst<x+2){
			continue;
		}
		ansf=ansf+(Suf[x+2][i]-Suf[lst][i])*r[x][i];
	}
}

这样,时间复杂度降为 \(\mathcal{O(nm)}\),不超时。

最后,注意取模 \(998244353\),还有多测要清空,不开 long long 见祖宗。

\(\texttt{code}\)

/*Written by smx*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define QAQ cout<<"QAQ\n";
const int MAXN=1e3+5,inf=1e18,mod=998244353;
int n,m,C,F,ansc,ansf;
char a[MAXN][MAXN];
int r[MAXN][MAXN],suf[MAXN][MAXN],d[MAXN][MAXN],Suf[MAXN][MAXN];
void init(){
	ansc=ansf=0;
	for(int i=1;i<=n+1;i++){
		for(int j=1;j<=m+1;j++){
			r[i][j]=suf[i][j]=d[i][j]=Suf[i][j]=0;
		}
	}
}
signed main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int T,id;
	cin>>T>>id;
	while(T--){
		init();
		cin>>n>>m>>C>>F;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				cin>>a[i][j];
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=m;j>=1;j--){
				if(a[i][j]=='1'){
					r[i][j]=0;
				}else{
					r[i][j]=r[i][j+1]+1;
				}
			}
		}
		for(int i=1;i<=n;i++){
			for(int j=m;j>=1;j--){
				if(r[i][j]!=0){
					r[i][j]--;
				}
			}
		}
		for(int i=n;i>=1;i--){
			for(int j=1;j<=m;j++){
				suf[i][j]=(suf[i+1][j]+r[i][j])%mod;
			}
		}
		for(int i=1;i<=m;i++){
			int lst=n+1;
			for(int x=n;x>=1;x--){
				if(a[x][i]=='1'){
					lst=x;
					continue;
				}
				if(lst<x+2){
					continue;
				}
				ansc=(ansc+(suf[x+2][i]-suf[lst][i]+mod)%mod*r[x][i]%mod)%mod;
			}
		}
		for(int i=n;i>=1;i--){
			for(int j=1;j<=m;j++){
				if(a[i][j]=='1'){
					d[i][j]=0;
				}else{
					d[i][j]=d[i+1][j]+1;
				}
			}
		}
		for(int i=n;i>=1;i--){
			for(int j=1;j<=m;j++){
				if(d[i][j]!=0){
					d[i][j]--;
				}
			}
		}
		for(int i=n;i>=1;i--){
			for(int j=1;j<=m;j++){
				Suf[i][j]=(Suf[i+1][j]+r[i][j]*d[i][j]%mod)%mod;
			}
		}
		for(int i=1;i<=m;i++){
			int lst=n+1;
			for(int x=n;x>=1;x--){
				if(a[x][i]=='1'){
					lst=x;
					continue;
				}
				if(lst<x+2){
					continue;
				}
				ansf=(ansf+(Suf[x+2][i]-Suf[lst][i]+mod)%mod*r[x][i])%mod;
			}
		}
		cout<<ansc*C%mod<<" "<<ansf*F%mod<<"\n";
	}
	return 0;
}

标签:后缀,int,题解,复杂度,lst,--,P8865,NOIP2022,mathcal
From: https://www.cnblogs.com/shimingxin1007/p/18593335

相关文章

  • ABC383E 题解
    ABC383E题解题意给定一张包含\(n\)个节点和\(m\)条无向带权边的图,以及两个序列\(A_k,B_k\)分别表示图中的某些节点,定义\(f(A_i,B_j)\)为从\(A_i\)到\(B_j\)所有路径各自包含的边权最大值中的最小值,可以任意排列\(B\)中的元素,使得\(\sum_{i=1}^kf(A_i,B_i)\)最......
  • Daiwa Securities Co. Ltd. Programming Contest 2024(AtCoder Beginner Contest 383)-C
    题目大意一个\(H\)行和\(W\)列的网格图。\((i,j)\)表示从上到下第\(i\)行和从左到下第\(j\)列的单元格。每个单元格用字符\(S_{i,j}\)表示。如果\(S_{i,j}\)为#,则该单元格有一个障碍物;如果\(S_{i,j}\)是.则该单元格是空的;如果\(S_{i,j}\)为H,则该单元网格图......
  • 【题解】洛谷P4198 楼房重建
    因为有个bool调了一个小时,汤碗里。题解显然能看到是斜率的问题,后面的斜率要严格大于前面的斜率才能够看见,所以这就是最大严格前缀长度问题。有修改考虑线段树维护,信息合并时并不能直接合并,左部分可以直接合并,但右部分不能超过左部分的斜率最大值,所以我们用函数递归右区间判断,如......
  • 关于网站icon小图标在网站上不显示的问题解决办法,确保图标正常显示
    解决网站icon小图标不显示的步骤检查文件路径:确保favicon.ico文件的路径正确。如果手动指定了图标路径,检查 <link> 标签中的 href 属性是否正确指向图标文件。检查文件格式:确保favicon.ico文件的格式正确。ICO文件是最常用的格式,但也可以使用PNG、JPEG等其他格式。如果使用......
  • NOIP 2024 题解
    NOIP2024题解T1首先对于两个串都不能动的位置,直接统计是否相等。对于连续的一段能动的位置,这一段的数可以随便交换,可以预处理每个位置属于哪一段,以及这一段中0和1的个数。我们贪心地考虑,优先匹配一个串能动,另一个串不能动的位置。可以感受到,先把不能动的位置匹配掉后,剩......
  • 2024 IntelliJ IDEA安装使用教程(附激活,含常见问题解答)
    第一步:下载IDEA安装包访问IDEA官网,下载IDEA也可以在这里点击下载idea(含博主使用版本)下载idea第二步:安装IDEA点击xx关掉程序!第三步:下载补丁IntelliJIDEA补丁文件点击获取补丁下载成功后,打开标注的文件文件夹,进入到文件夹/jetbra注意:这个文件夹单......
  • 洛谷P10244 String Minimization 题解
    题目传送门思路本题就是让你求\(a\)字典序最小时的\(b\),毕竟他说在\(a\)的字典序尽量小的前提下。接下来就做这个判断:如果\(a_i\)<\(c_i\),则\(b_i\)和\(d_i\)交换。如果\(a_i\)<\(c_i\)且\(b_i\)>\(d_i\),则\(b_i\)和\(d_i\)交换。其余情况不用交换。......
  • ABC382 C-F题解
    C-KaitenSushi把寿司都放到一个堆里,从前往后扫\(A\)数组,如果当前食客\(A_i\)小于等于堆顶,就取出堆顶,记录这份寿司被第\(i\)个人吃掉。复杂度\(O(n\logm)\)。D-KeepDistance搜索回溯,但每一步从\(10\)枚举到\(m\)会超时,剪一下枝for(inti=10;res.back()+......
  • 【题解】洛谷P6225: [eJOI2019] 异或橙子
    P6225[eJOI2019]异或橙子结论题,要手玩几组样例就懂了,发现长度为偶数的最后削为0,否则的话下标为奇数答案就是区间下标为奇数的异或和,偶数相同,所以考虑用两个树状数组分别维护下标奇偶数的异或前缀和,然后再异或区间。#include<bits/stdc++.h>//#defineintlonglong#define......
  • CF2045H - Missing Separators 题解
    CF2045H-MissingSeparators题面您有一本字典,它是按字母顺序排列的多个单词的列表。每个单词都由大写英文字母组成。您想打印这本字典。然而,打印系统出现了一个错误,列表中的所有单词都紧挨着打印,单词之间没有任何分隔符。现在,您最终得到的字符串\(S\)是字典中所有单词按照......