D、 Duration

题意:给出在同一天的某个时刻,输出这两个时刻之间的差值。
思路:签到题。简单暴力,直接以00:00:00为起点,计算两个时刻离这个时间点的时间,输出两者差值绝对值即可。
代码:

#include<iostream>
using namespace std;
int main(){
    int hh,mm,ss;
    scanf("%d:%d:%d",&hh,&mm,&ss);
    int num1=hh*3600+mm*60+ss;
    scanf("%d:%d:%d",&hh,&mm,&ss);
    int num2=hh*3600+mm*60+ss;
    cout<<abs(num1-num2)<<endl;
    return 0;
}

F、 Fake Maxpooling

题意:给出一个矩阵,求出这个矩阵的所有k阶子矩阵中的最大值的和。
思路:至于那个求出这个矩阵的元素怎么求就不说了,我还以为直接求会超时呢!对于取某一个范围内的最值的问题,一般就是两种思路,一种就是DP,另一种就是单调队列来做。这题更适合用单调队列的做法,我们只要对这个矩阵的每行每列用单调队列来维护它的最大值就可。
如果单调队列还不会建议先去做一些基础题目。
传送门先看看这个再回来吧。
了解了单调队列的基本原理和实现之后。我们来说说怎么来维护行,其实很简单,只要对每行进行一个区间长为k维护最大值就行了,同时把最大值放在mmax数组里面。

for(int i=1;i<=n;i++){  //对每一行的各列进行一个单调队列维护区间为k的最大值
        int head=0,tail=0;
        for(int j=1;j<=m;j++){
            while(head<tail&&a[i][j]>a[i][que[tail-1]])  tail--;
            que[tail++]=j;
            while(head<tail&&que[tail-1]-que[head]+1>h)  head++;
            if(j>=h)  mmax[i][j]=a[i][que[head]];
        }
    }

同理,我们这样来维护列。这里我们直接更新的是行下标超过k或列下标超过k的那些位置,也就是可以作为一个k阶矩阵的右下角的那些位置。

for(int j=h;j<=m;j++){  //对每一列的各行进行一个单调队列的维护区间为k的最大值
        int head=0,tail=0;
        for(int i=1;i<=n;i++){
            while(head<tail&&mmax[i][j]>mmax[que[tail-1]][j])  tail--;
            que[tail++]=i;
            while(head<tail&&que[tail-1]-que[head]+1>h)  head++;
            if(i>=h)  sum+=mmax[que[head]][j];  //维护之后我们直接累加这个矩阵为k的最大值即可。
        }
    }

ac代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=5010;
typedef long long ll;
int a[maxn][maxn],n,m,h,mmax[maxn][maxn],que[maxn];
int gcd(int x,int y){
    if(y==0)  return x;
    else  return gcd(y,x%y);
}
int lcm(int x,int y){
    return x*y/gcd(x,y);
}
int main(){
    cin>>n>>m>>h;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;++j){
            a[i][j]=lcm(i,j);
        }
    }
    for(int i=1;i<=n;i++){  //对每一行的各列进行一个单调队列维护区间为k的最大值
        int head=0,tail=0;
        for(int j=1;j<=m;j++){
            while(head<tail&&a[i][j]>a[i][que[tail-1]])  tail--;
            que[tail++]=j;
            while(head<tail&&que[tail-1]-que[head]+1>h)  head++;
            if(j>=h)  mmax[i][j]=a[i][que[head]];
        }
    }
    ll sum=0;
    for(int j=h;j<=m;j++){  //对每一列的各行进行一个单调队列的维护区间为k的最大值
        int head=0,tail=0;
        for(int i=1;i<=n;i++){
            while(head<tail&&mmax[i][j]>mmax[que[tail-1]][j])  tail--;
            que[tail++]=i;
            while(head<tail&&que[tail-1]-que[head]+1>h)  head++;
            if(i>=h)  sum+=mmax[que[head]][j];
        }
    }
    cout<<sum<<endl;
    return 0;
}