本来想写的速成日志也没写多少,cb国二,最后一题树形DP调了一小时发现h数组没置 -1,最后无果,如果没马虎可能有国一水平了,正儿八经准备用了两个月,因为要考研,每天只学2 - 3小时的算法,一共刷了300多道题吧,由于之前选过ACM(实验课因为周六去,懒得去还给我挂了)和算法分析课,所以还是有点基础的,如果算上一年前刷的题总共加起来也就400多道题吧。
说一下历程吧,一年前的题都是老师布置的作业,迫不得已做的,不过对算法有了个大概的了解,算是入门;省赛之前做的洛谷热度最高的题单,做了大概170 180道题,省一排名比较靠后;省赛之后想了想还是准备一下吧,跟着y总的ACWing的蓝桥杯辅导课和每日一题大概做了80道题,期间穿插的刷了刷洛谷的同类型题,一共大概130 140道题。
本想搞个速成日志的,不过我发现速成不适合搞日志,只有那些长时间刷题打ACM的大佬,刷题刷到瓶颈写写日志博客才有用,像我这种速成的,刷题都来不及更别说写博客了。。
不说了,明天考6级,对于考研党来说6级的成绩还是很重要的,祝大家都能得偿所愿未来都能上岸。*
完结撒花❀
单调队列
只要使用单调队列分别维护行和列,就可以了
如果不明白什么是单调队列,可以看一下这个题
P1886 滑动窗口 /【模板】单调队列
该题和P2216 [HAOI2007]理想的正方形十分相似,只是多了一个模运算,但恰恰这个模运算,卡了我1个多小时。。。
#include <bits/stdc++.h>
//这个题一度让我以为代码某处的逻辑有误,但是使用该代码可以AC理想的正方形,于是就一直在研究细节。。一个模运算卡了我一个小时。。
using namespace std;
#define ll long long
const int N = 1005;
const int mod = 998244353;
int n,m,a,b,ans,g[N][N],mm[N][N],MM[N][N];
int minr[N][N],minc[N][N],maxr[N][N],maxc[N][N];
void monotonic_row(){
memset(mm,0,sizeof mm);
memset(MM,0,sizeof MM);
for(int i = 1; i <= n; i ++ ){
int head_min=1,last_min=0;
int head_max=1,last_max=0;
int p_min[N],p_max[N];
for(int j = 1; j <= m; j ++ ){
while(head_min <= last_min && g[i][j] <= mm[i][last_min]){
last_min--;
}
while(head_max <= last_max && g[i][j] >= MM[i][last_max]){
last_max--;
}
mm[i][++ last_min] = g[i][j];
p_min[last_min] = j;
MM[i][++ last_max] = g[i][j];
p_max[last_max] = j;
while(p_min[head_min] <= j - b){
head_min ++ ;
}
while(p_max[head_max] <= j - b){
head_max ++ ;
}
if(j >= b) minr[i][j] = mm[i][head_min] ,maxr[i][j] = MM[i][head_max];
}
}
}
void monotonic_colum(){
memset(mm,0,sizeof mm);
memset(MM,0,sizeof MM);
for(int i = 1; i <= m; i ++ ){
int head_min=1,last_min=0;
int head_max=1,last_max=0;
int p_min[N],p_max[N];
for(int j = 1; j <= n; j ++ ){
while(head_min <= last_min && minr[j][i] <= mm[last_min][i]){
last_min--;
}
while(head_max <= last_max && maxr[j][i] >= MM[last_max][i]){
last_max--;
}
mm[++ last_min][i] = minr[j][i];
p_min[last_min] = j;
MM[++ last_max][i] = maxr[j][i];
p_max[last_max] = j;
while(p_min[head_min] <= j - a){
head_min ++ ;
}
while(p_max[head_max] <= j - a){
head_max ++ ;
}
if(j >= a) minc[j][i] = mm[head_min][i] ,maxc[j][i] = MM[head_max][i];
}
}
}
int main()
{
scanf("%d%d%d%d", &n, &m, &a, &b);
for(int i = 1; i <= n; i ++ ){
for(int j = 1;j <= m; j ++ ){
scanf("%d", &g[i][j]);
}
}
monotonic_row();
monotonic_colum();
for(int i = a; i <= n; i ++ ){
for(int j = b ; j <= m ; j ++ ){
// ans= ( ans + ( minc[i][j] % mod ) * ( maxc[i][j] % mod ) ) % mod;//错误的,虽然两个数都模上mod,但是两数相乘的结果仍然可能超过int范围,导致结果错误
// ans= ( ans + ( ( minc[i][j] % mod ) * ( maxc[i][j] % mod ) ) % mod ) % mod;//错误的,同上,对已经越界的数进行模运算,得到的结果仍然是错误的
ans= ( ans + ( (ll) minc[i][j] * maxc[i][j] ) ) % mod;//正确的
}
}
printf("%d",ans);
return 0;
}