首页 > 其他分享 >维护集合两元素最大乘积

维护集合两元素最大乘积

时间:2023-05-14 21:13:20浏览次数:36  
标签:max1 大值 乘积 int 最大值 元素 long max2 集合

维护集合两元素最大乘积

给出多个集合,不断合并集合,要求求出最大集合中任意两个元素乘积的最大值

顾名思义,我们求最大值和次大值相乘一定最大

我们考虑到可能为负值,所以我们还需要维护最小值,和次小值

怎么维护呢?怎么把操作写的漂亮?

规定a序列为更新工具

维护b的最大值和次大值

    if(max1[a] >= max1[b]){//如果a的最大值大于等于b的最大值
                           //为啥是小于等于,因为我们需要顾及b的次大值是否需要更新
        max1[b] = max1[a];//b的最大值更新
        max2[b] = max(max1[b],max2[a]);//b的次大值只会存在于b的原最大值和a的次大值之中,毕竟默认的我们已知b的原最大值大于原次最大值
    }
    else if(max1[a] > max2[b])max2[b]=max1[a];//b的最大值不会被替代,那么只需要考虑b的次大值会不会被替代,而且a的最大值大于a的次大值,故只需要比较a的最大值和b的次大值的大小
    if(min1[a] <= min1[b]){最小值同理
        min1[b] = min1[a];
        min2[b] = min(min1[b],min2[a]);
        
    }
    else if(min1[a] < min2[b]) min2[b] = min1[a];
    maxx = max(maxx,max(max1[b] * max2[b],min1[b] * min2[b]));
    求一下最大乘积

应用

P2178 [NOI2015] 品酒大会

没错,这就是SA的题目,见博客适合于everyone的后缀数组

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<cmath>
#include<vector>
#define M 1000050
using namespace std;

int n,m,l;
const long long inf=2e20;
string s,ss;
long long w[M],siz[M],fa[M];
long long max1[M],max2[M],min1[M],min2[M];
int y[M],x[M],c[M],sa[M],rk[M],height[M],maxn=0;
long long ans[M][2];
vector<int>fam[M];

void get_sa(){
    for(int i=1;i<=n;++i) ++c[x[i]=s[i]];
    for(int i=2;i<=m;++i) c[i]+=c[i-1];
    for(int i=n;i>=1;--i) sa[c[x[i]]--]=i;
    for(int k=1;k<=n;k<<=1){
        int num=0;
        // for(int i=1;i<=num;i++) numm[i]=0;
        for(int i=n-k+1;i<=n;++i) y[++num]=i;
        for(int i=1;i<=n;++i) if(sa[i]>k) y[++num]=sa[i]-k;
        for(int i=1;i<=m;++i) c[i]=0;
        for(int i=1;i<=n;++i) maxn=max(maxn,++c[x[i]]);
        for(int i=2;i<=m;++i) c[i]+=c[i-1];
        for(int i=n;i>=1;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
        swap(x,y);
        x[sa[1]]=1;
        num=1;
        for(int i=2;i<=n;++i){
            if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) {
                x[sa[i]]=num;
                // ++numm[num];
            }
            else {
                x[sa[i]]=++num;
            }
        }
        if(num==n)break;
        m=num;
    }

}

void get_lcp(){
    int k=0;
    for(int i=1;i<=n;++i)rk[sa[i]]=i;
    for(int i=1;i<=n;++i){
        if(rk[i]==1)continue;
        if(k)--k;
        int j=sa[rk[i]-1];
        while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k])++k;
        height[rk[i]]=k;
    }
}

int find(int x){
    if(fa[x]!=x)fa[x]=find(fa[x]);
    return fa[x];
}

long long C(long long x){
    return (long long)1ll*x*(x-1)/2;
}

void val(int r){
    static long long cnt=0,maxx=-inf;
    for(auto x:fam[r]){
        int a=find(x-1),b=find(x);
        cnt-=C(siz[a])+C(siz[b]);
        fa[a]=b;
        siz[b]+=siz[a];
        cnt+=C(siz[b]);
        if(max1[a]>=max1[b]){
            max2[b]=max(max1[b],max2[a]);
            max1[b]=max1[a];
        }
        else if(max1[a]>max2[b])max2[b]=max1[a];
        if(min1[a]<=min1[b]){
            min2[b]=min(min1[b],min2[a]);
            min1[b]=min1[a];
        }
        else if(min1[a]<min2[b])min2[b]=min1[a];
        maxx=max(maxx,max(max1[b]*max2[b],min1[b]*min2[b]));
    }
    if(maxx==-inf)ans[r][0]=cnt,ans[r][1]=0;
    else ans[r][0]=cnt,ans[r][1]=maxx;
}

int main(){

    scanf("%d",&n);cin>>ss;
    l=ss.size();s='0';
    for(int i=1;i<=n;++i)cin>>w[i];
    for(int i=0;i<ss.size();i++)s+=ss[i];
    m=122;
    get_sa();
    get_lcp();
    for(int i=2;i<=n;++i)fam[height[i]].push_back(i);
    for(int i=1;i<=n;++i){
        fa[i]=i;siz[i]=1;
        max1[i]=min1[i]=w[sa[i]];/*1正2负*/
        max2[i]=-inf;min2[i]=inf;
    }
    for(int i=n-1;i>=0;--i)val(i);//倒序处理
    for(int i=0;i<n;++i) printf("%lld %lld \n",ans[i][0],ans[i][1]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}



标签:max1,大值,乘积,int,最大值,元素,long,max2,集合
From: https://www.cnblogs.com/iruiforever/p/17400198.html

相关文章

  • 算法刷题系列之移除元素:快慢指针技巧
    题目+日期移除元素2023年5月14日17点50分基础知识暴力解法这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素,第二个for循环更新数组。双指针法(快慢指针法)通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。定义快慢指针快指针:寻找新数组的元......
  • LeetCode 347. 前 K 个高频元素
    题目链接:LeetCode347.前K个高频元素题意:给你一个整数数组nums和一个整数k,请你返回其中出现频率前k高的元素。你可以按任意顺序返回答案。解题思路:(哈希表,计数排序)O(n)首先用哈希表统计出所有数出现的次数。由于所有数出现的次数都在1到n之间,所以我们可以......
  • 【❂Java集合】循环链表和双向链表的区别是是什么
    最后一个结点指针指向不同在建立一个循环链表时,必须使其最后一个结点的指针指向表头结点,而不是像双向链表那样置为NULL。此种情况还用于在最后一个结点后插入一个新的结点。判断链域值不同在判断是否到表尾时,是判断该结点链域的值是否是表头结点,当链域值等于表头指针时,说明已到......
  • #yyds干货盘点# LeetCode面试题:乘积最大子数组
    1.简述:给你一个整数数组nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。测试用例的答案是一个 32-位整数。子数组是数组的连续子序列。 示例1:输入:nums=[2,3,-2,4]输出:6解释: 子数组[2,3]有最大乘积6。示例......
  • MongoDB 功能详解之时间序列集合(Time Series Collections)
    MongoDB功能详解之时间序列集合(TimeSeriesCollections)      时间序列集合(TimeSeriesCollections):MongoDB5.0版本中的新功能。时间序列数据是一系列数据点,通过分析这些随时间变化的数据点而获得对数据的深刻理解。时间序列数据通常由以下组成部分组成:时间:数......
  • 通配符的匹配很全面, 但无法找到元素 ‘aop:config’ 的声明问题的解决
    问题描述在我根据教程视频一步步将所有文件配置完成之后,就显示出来这个错误!问题解决将下面两个语句放置到applicationContext.xml配置文件的约束里面即可解决问题:xmlns:aop="http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aophttp://ww......
  • 【数组01】二分查找&移除元素
    TableofContents二分查找704.二分查找35.搜索插入位置34.在排序数组中查找元素的第一个和最后一个位置69.x的平方根367.有效完全平方数移除元素27.移除元素26.删除排序数组中的重复项283.移动零844.比较含退格的字符串977.有序数组的平方Solutions7......
  • 代码随想录算法训练营第三天|203.移除链表元素 、707.设计链表 、206.反转链表
    一.链表基础1.最后一个节点的指针域指向null(空指针的意思)。2.链表在内存中不是连续分布的。3.链表的长度可以是不固定的,并且可以动态增删,适合数据量不固定,频繁增删,较少查询的场景。1#链表节点的定义2classListNode:3def__init__(self,val,next=None):4......
  • ant-design-vue中,如何将固定头部(layout-header)中的menu-item元素移动到右边
    官方的文档显示的都是左边,提供的API也没有移动到右边的功能 在ant-design-vue的群里面问了,然后又去各种问。有人建议可以用row和col来解决,也是可以,但是为了保持格式完整性,最好是在menu中去修改,不然,按键和其他按键不一样,很麻烦。去ant-design(ant-design-vue算是ant-design的分......
  • List 集合手动分页的方法总结
    前言在工作中难免会遇到,将组装的集合数据进行分页处理,现在我将自己手动分页的三种方法进行总结,有不对的地方敬请大家批评指正!一、数据准备//当前页intpageIndex=1;//页长intpageSize=10;List<UserEntity>userList=newArrayList<>();userList.add(UserEnt......