2020牛客暑期多校训练营(第二场)F.Fake Maxpooling

这个题目就是用一个二维单调队列,但是比赛的时候就是没有想到,更奇葩的是我居然连题目都读错了,读成了求在nm矩阵里找一个kk大小的使得这个kk的矩阵的值的和最大,而题目本来的意思是求每一个kk矩阵里面的最大值然后加起来,lcj做出来后说是二维单调队列我当时一脸懵逼,首先我是读错了题目,然后是二维单调队列没看见过,不知道长哪样,我还是太菜了。

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<algorithm>
#include<deque>
#include<map>
#include<stdlib.h>
#include<set>
#include<iomanip>
#include<stack>
#define ll long long
#define ull unsigned long long
#define ms(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x & -x
#define fi first
#define se second
#define lson num<<1
#define rson num<<1|1
#define bug cout<<"----acac----"<<endl
#define IOS ios::sync_with_stdio(false), cin.tie(0),cout.tie(0)
using namespace std;
const int maxn = 2e5+ 50;
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;
const ll  lnf  = 0x3f3f3f3f3f3f3f3f;
const ll mod = 23333;
const  double pi=3.141592653589;
int a[5005][5005],n,m,k,ma[5005][5005];
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
int q[5005];
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            a[i][j]=(i*j)/gcd(i,j);
        }
    }
    for(int i=1;i<=n;i++)
    {
        int tail=0,head=0;
        for(int j=1;j<=m;j++)
        {
            while(tail>head&&a[i][q[tail-1]]<=a[i][j])tail--;//使得队列是递增的
            q[tail++]=j;
            while(tail>head&&j-q[head]>=k)head++;//保证队列维护的是k这么大的区间,而且必须是等于,不然会wa到哭
            ma[i][j]=a[i][q[head]];
        }
    }
    ll ans=0;
    for(int j=1;j<=m;j++)
    {
        int tail=0,head=0;
        for(int i=1;i<=n;i++)
        {
            while(tail>head&&ma[q[tail-1]][j]<=ma[i][j])tail--;//看清楚了,这是ma是上一次求的这一行的最大值
            q[tail++]=i;
            while(tail>head&&i-q[head]>=k)head++;
            if(j>=k&&i>=k)//这个一定要加,不然会连输出都不对
            ans+=ma[q[head]][j];
        }
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qcccc_/article/details/107360109