Acwing第45次周赛题解

第一题签到题就不讲了【只要是个人就会好吧】

然后是第二题,这个题是一个最长连续子序列的一个扩展题,只不过是条件不同了罢了;

先看题:

所以我们用的是双指针算法跟哈希表;

因为每个数字的范围都很小,所以不用特地写哈希表,直接一个数组就可以了,即ha[i]存储i这个数字在当前范围内出现的次数;

定义一个变量qua,存储当前范围内不同数的个数

然后我们的指针i、j从1开始,进行以下循环:

(1)j指向数字A

~如果ha[A]==0,那么qua++,ha[A]++;

~ha[A]!=0,那么只要ha[A]++;

(2)如果qua>k

1:ha[i]--;

~:如果ha[i]==0,那么que--,i++

~:否则只i++

那么下面是具体代码:

#include<iostream>
#include<algorithm>
using namespace std;

const int N=500010;

int ha[N];
int st[N];
int n,k;
int qua;
int l,r;

int main(){
    
    cin>>n>>k;
    
    for(int i=1;i<=n;i++) scanf("%d",&st[i]);
    
    for(int i=1,j=1;j<=n;j++){
        
        if(ha[st[j]]!=0) ha[st[j]]++;
        else ha[st[j]]++,qua++;
        
        while(qua>k){
            ha[st[i]]--;
            if(!ha[st[i]]) qua--;
            i++;
        }
        
        if(r-l+1<=j-i+1) r=j,l=i;
        
    }
    
    cout<<l<<' '<<r;
}

那么是下一道......题

 我们先抽象一下我们要干的事情:

其实就在a、b数组找一段连续区间,然后对两个区间分别求和,如何相乘,得到的结果小于x,在这种区间之间,我们要找到两段长度相乘最大的那个;

那么我们要怎么写呢?

这里我们要用到单调栈的思想:

要明确一个结论:长度相同的区间,和越小越好;

领悟了这句话,那么就可以用o(n^2)的时间复杂度算出来了:

我们对两个数组进行处理,最后得到两个组数据:

a1[i]存储着长度为i的区间和最小值,b1[i]同理;

然后我们a1、b1数组进行遍历寻找答案;

下面是代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;

const int N=2010;

ll oa[N],ob[N];
ll a[N],b[N];
ll fixa[N],fixb[N];
ll n,m,x;
ll ans;

int main(){
    
    cin>>n>>m;
    
    memset(oa,0x3f,sizeof oa); memset(ob,0x3f,sizeof ob);
    
    for(int i=1;i<=n;i++) cin>>a[i],fixa[i]=fixa[i-1]+a[i];
    for(int i=1;i<=m;i++) cin>>b[i],fixb[i]=fixb[i-1]+b[i];
    
    cin>>x;
    
    for(int len=1;len<=n;len++){
        
        for(int i=1;i+len-1<=n;i++){
            
            int j=i+len-1;
            
            ll sum=fixa[j]-fixa[i-1];
            
            oa[len]=min(oa[len],sum);
        }
    }
    
    for(int len=1;len<=m;len++){
        
        for(int i=1;i+len-1<=m;i++){
            
            int j=i+len-1;
            
            ll sum=fixb[j]-fixb[i-1];
            
            ob[len]=min(ob[len],sum);
        }
    }
    
    for(int i=1;i<=n;i++){
        
        for(int j=1;j<=m;j++){
            
            if(oa[i]*ob[j]<=x) ans=max((ll)i*j,ans);
            
        }
    }

    cout<<ans;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值