SGU421: K-th Product 题解

本文探讨了在面对大量整数运算时如何优化程序效率,包括使用哈希表减少重复计算、改进高精度乘法算法及调整数据存储方式等策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题贼难写…但我觉得锻炼代码能力和思维都是非常好的
我们先考虑全是正数的情况,这种情况是比较简单的,考虑到k10000k≤10000,这种题目的套路都是把一个初始状态扔进一个大根堆,每次取堆顶元素后把它能扩展到的元素扔进堆
刚开始的最大值肯定是取最大的前mm个数,设初始序列是1.2.3…m
对于一个我当前取的序列,它能扩展到的序列一定是只有一位向后移了一格的一个序列,因为m13,所以状态数不会太多
注意数字可能会非常大,所以要写高精度(恶心)
下面考虑有负数的情况
我们发现可以把正数和负数分开来考虑;我们先考虑乘积是非负数,这时负数一定取偶数个,然后把正数和负数按照绝对值从大到小排序就和上面一样了,乘积是负数,则负数一定取奇数个,然后把正数和负数按绝对值从小到大排序就和上面一样了


貌似题目已经做完了,但噩梦才刚刚开始
假设你已经写出了一个不错的程序,这时你通常会得到tle on test 20
跑一跑极限数据,发现开了O2竟然要跑9s
于是就开始了漫漫卡常路(之后的时间都是开了O2测的)
首先考虑用哈希替换map,map是在向堆里加新元素用到的,因为你要保证加进去的元素不重复,而事实上一个序列是可能有多种方法被扩展出来的
写完哈希以后,成功从9s减到3s
然后考虑优化高精度的常数,这里有一个常见的小技巧
我们通常会开一个数组,每一个元素存一位数字,但事实上两个int在做乘法的时候,数字小并不会变快
所以我们改变一下策略,每个元素存7位数字,这样我的数字的最大位数就会大大减小,做乘法是O(n2)O(n2)的,相当于优化了更多
这个地方有一个小细节要注意一下:每7位一存的话,除了最高位,其他的要补前导零
优化完高精度的常数,成功的从3s优化到2s(效果好像没有预期的明显啊)
考虑到每7位一存的话要开LL,运行速度会变慢,所以改成了每3位一存,这样int就能解决,优化到了1.4s(这是个玄学)


到了这里,卡常死活卡不动了,然而这题要求0.75s
我们尝试开始考虑优化算法(什么这个算法还能优化…)
这个哈希表其实是非常慢的,因为cmp一次的代价是O(m)O(m)的,尝试在这里做文章
我们为什么要哈希?因为同一个序列不能出现多次,而事实上同一个序列可能有很多种不同的扩展方式
那我们能不能通过限定扩展方式,使得序列不会重复出现?
是可以的,我们只要规定一个扩展的顺序,例如,对于正数和负数,我都规定如果这次你把第i个数向后移了一位得到了新的状态,那么下一次你不能再移动i+1~m
这样对于任意一个序列,他的扩展方式都是唯一的,只有先移最后一个元素到指定位置,然后移倒数第二个…以此类推
这样把哈希表省掉了,这是一个大优化
时间卡到了0.2s,不开O2 0.4s,OK可以过了


Code

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=998244353;
const LL LINF=2e16;
const int INF=1e9;
const int magic=348;
const double eps=1e-10;
const double pi=3.14159265;

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

struct Bigint
{
    int b[30],len;
    inline void clear() {memset(b,0,sizeof(b));len=1;}
    inline void read(int x) {clear();for (len=0;x;x/=1000) b[++len]=x%1000;if (!len) len=1;}
    inline void print()
    {
        for (register int i=len;i;i--)
        {
            if (i==len) {printf("%d",b[i]);continue;}
            int cnt=0,tt=100;
            while (b[i]<tt) cnt++,tt/=10;
            while (cnt--) printf("0");
            if (b[i]) printf("%d",b[i]);
        }
    }
    inline bool operator < (const Bigint &x) const
    {
        if (len!=x.len) return len<x.len;
        for (register int i=len;i>=1;i--)
            if (b[i]!=x.b[i]) return b[i]<x.b[i];
        return true;
    }
    inline bool operator > (const Bigint &x) const
    {
        if (len!=x.len) return len>x.len;
        for (register int i=len;i>=1;i--)
            if (b[i]!=x.b[i]) return b[i]>x.b[i];
        return true;
    }
    inline Bigint operator + (const Bigint x)
    {
        Bigint res;res.clear();
        for (register int i=1;i<=max(len,x.len);i++)
        {
            res.b[i]+=b[i]+x.b[i];
            res.b[i+1]+=res.b[i]/1000;res.b[i]%=1000;
        }
        res.len=max(len,x.len);if (res.b[res.len+1]) res.len++;
        return res;
    }
    inline Bigint operator * (const Bigint x)
    {
        Bigint res;res.clear();int i,j;
        for (i=1;i<=len;i++)
            for (j=1;j<=x.len;j++)
                res.b[i+j-1]+=b[i]*x.b[j];
        for (i=1;i<=len+x.len-1;i++) res.b[i+1]+=res.b[i]/1000,res.b[i]%=1000;
        res.len=len+x.len-1;if (res.b[res.len+1]) res.len++;
        return res;
    }
};

int n,m,k;
int a[10048];
Bigint pos[10048],neg[10048];int ptot,ntot;
Bigint res[71048];int rtot;

inline int myabs(int x) {return x>=0?x:-x;}
inline bool cmp_big(Bigint x,Bigint y) {return x>y;}
inline bool cmp_small(Bigint x,Bigint y) {return x<y;}

struct node_pos
{
    Bigint val;
    short pnum,nnum,npos[20],ppos[20];
    bool cur;int cpos;
    inline bool operator < (const node_pos &x) const {return val<x.val;}
};

priority_queue<node_pos> qpos;
inline void Getpos(short pnum,short nnum)
{
    int i,j,cnt;node_pos ins,cur;
    ins.pnum=pnum;ins.nnum=nnum;ins.val.clear();ins.val.b[1]=1;ins.val.len=1;
    for (i=1;i<=pnum;i++) ins.ppos[i]=i,ins.val=ins.val*pos[i];
    for (i=1;i<=nnum;i++) ins.npos[i]=i,ins.val=ins.val*neg[i];
    ins.cur=false;ins.cpos=pnum;
    while (!qpos.empty()) qpos.pop();
    qpos.push(ins);cnt=0;
    while (!qpos.empty() && cnt<k)
    {
        cur=qpos.top();qpos.pop();
        cnt++;res[++rtot]=cur.val;
        if (!cur.cur)
        {
            for (i=1;i<=cur.cpos;i++)
                if (cur.ppos[i]<ptot && (i==pnum || cur.ppos[i+1]!=cur.ppos[i]+1))
                {
                    ins.cpos=i;ins.cur=false;
                    for (j=1;j<=pnum;j++) ins.ppos[j]=cur.ppos[j];
                    for (j=1;j<=nnum;j++) ins.npos[j]=cur.npos[j];
                    ins.ppos[i]++;ins.val.clear();ins.val.len=1;ins.val.b[1]=1;
                    for (j=1;j<=pnum;j++) ins.val=ins.val*pos[ins.ppos[j]];
                    for (j=1;j<=nnum;j++) ins.val=ins.val*neg[ins.npos[j]];
                    qpos.push(ins);
                }
            for (i=nnum;i<=nnum && i;i++)
                if (cur.npos[i]<ntot && (i==nnum || cur.npos[i+1]!=cur.npos[i]+1))
                {
                    ins.cpos=i;ins.cur=true;
                    for (j=1;j<=pnum;j++) ins.ppos[j]=cur.ppos[j];
                    for (j=1;j<=nnum;j++) ins.npos[j]=cur.npos[j];
                    ins.npos[i]++;ins.val.clear();ins.val.len=1;ins.val.b[1]=1;
                    for (j=1;j<=pnum;j++) ins.val=ins.val*(pos[ins.ppos[j]]);
                    for (j=1;j<=nnum;j++) ins.val=ins.val*(neg[ins.npos[j]]);
                    qpos.push(ins);
                }
        }
        else
        {
            for (i=1;i<=cur.cpos;i++)
                if (cur.npos[i]<ntot && (i==nnum || cur.npos[i+1]!=cur.npos[i]+1))
                {
                    ins.cpos=i;ins.cur=true;
                    for (j=1;j<=pnum;j++) ins.ppos[j]=cur.ppos[j];
                    for (j=1;j<=nnum;j++) ins.npos[j]=cur.npos[j];
                    ins.npos[i]++;ins.val.clear();ins.val.len=1;ins.val.b[1]=1;
                    for (j=1;j<=pnum;j++) ins.val=ins.val*(pos[ins.ppos[j]]);
                    for (j=1;j<=nnum;j++) ins.val=ins.val*(neg[ins.npos[j]]);
                    qpos.push(ins);
                }
        }   
    }
}

struct node_neg
{
    Bigint val;
    short pnum,nnum,ppos[20],npos[20];
    bool cur;int cpos;
    inline bool operator < (const node_neg &x) const {return val>x.val;}
};

priority_queue<node_neg> qneg;
inline void Getneg(short pnum,short nnum)
{
    int i,j,cnt;node_neg ins,cur;
    ins.pnum=pnum;ins.nnum=nnum;ins.val.clear();ins.val.b[1]=1;ins.val.len=1;
    for (i=1;i<=pnum;i++) ins.ppos[i]=i,ins.val=ins.val*pos[i];
    for (i=1;i<=nnum;i++) ins.npos[i]=i,ins.val=ins.val*neg[i];
    ins.cur=false;ins.cpos=pnum;
    while (!qneg.empty()) qneg.pop();
    qneg.push(ins);cnt=0;
    while (!qneg.empty() && cnt<k)
    {
        cur=qneg.top();qneg.pop();
        cnt++;res[++rtot]=cur.val;
        if (!cur.cur)
        {
            for (i=1;i<=cur.cpos;i++)
                if (cur.ppos[i]<ptot && (i==pnum || cur.ppos[i+1]!=cur.ppos[i]+1))
                {
                    ins.cpos=i;ins.cur=false;
                    for (j=1;j<=pnum;j++) ins.ppos[j]=cur.ppos[j];
                    for (j=1;j<=nnum;j++) ins.npos[j]=cur.npos[j];
                    ins.ppos[i]++;ins.val.clear();ins.val.len=1;ins.val.b[1]=1;
                    for (j=1;j<=pnum;j++) ins.val=ins.val*pos[ins.ppos[j]];
                    for (j=1;j<=nnum;j++) ins.val=ins.val*neg[ins.npos[j]];
                    qneg.push(ins);
                }
            for (i=nnum;i<=nnum && i;i++)
                if (cur.npos[i]<ntot && (i==nnum || cur.npos[i+1]!=cur.npos[i]+1))
                {
                    ins.cpos=i;ins.cur=true;
                    for (j=1;j<=pnum;j++) ins.ppos[j]=cur.ppos[j];
                    for (j=1;j<=nnum;j++) ins.npos[j]=cur.npos[j];
                    ins.npos[i]++;ins.val.clear();ins.val.len=1;ins.val.b[1]=1;
                    for (j=1;j<=pnum;j++) ins.val=ins.val*(pos[ins.ppos[j]]);
                    for (j=1;j<=nnum;j++) ins.val=ins.val*(neg[ins.npos[j]]);
                    qneg.push(ins);
                }
        }
        else
        {
            for (i=1;i<=cur.cpos;i++)
                if (cur.npos[i]<ntot && (i==nnum || cur.npos[i+1]!=cur.npos[i]+1))
                {
                    ins.cpos=i;ins.cur=true;
                    for (j=1;j<=pnum;j++) ins.ppos[j]=cur.ppos[j];
                    for (j=1;j<=nnum;j++) ins.npos[j]=cur.npos[j];
                    ins.npos[i]++;ins.val.clear();ins.val.len=1;ins.val.b[1]=1;
                    for (j=1;j<=pnum;j++) ins.val=ins.val*(pos[ins.ppos[j]]);
                    for (j=1;j<=nnum;j++) ins.val=ins.val*(neg[ins.npos[j]]);
                    qneg.push(ins);
                }
        }
    }
}

Bigint tmp[400048];int fl;
inline void merge_sort(int left,int right)
{
    if (left>=right) return;
    int mid=(left+right)>>1,k1,k2,pt;
    merge_sort(left,mid);merge_sort(mid+1,right);
    for (k1=left,k2=mid+1,pt=left;k1<=mid && k2<=right;)
        if (fl==1)
        {
            if (res[k1]<res[k2]) tmp[pt++]=res[k1++]; else tmp[pt++]=res[k2++];
        }
        else
        {
            if (res[k1]>res[k2]) tmp[pt++]=res[k1++]; else tmp[pt++]=res[k2++];
        }
    for (;k1<=mid;) tmp[pt++]=res[k1++];
    for (;k2<=right;) tmp[pt++]=res[k2++];
    for (pt=left;pt<=right;pt++) res[pt]=tmp[pt];
}

int main ()
{
    int i,j;
    n=getint();m=getint();k=getint();
    for (i=1;i<=n;i++)
    {
        a[i]=getint();
        if (a[i]>=0) pos[++ptot].read(a[i]); else neg[++ntot].read(-a[i]);
    }
    for (i=1;i<=ptot;i++) res[i]=pos[i];
    fl=0;merge_sort(1,ptot);
    for (i=1;i<=ptot;i++) pos[i]=res[i];
    for (i=1;i<=ntot;i++) res[i]=neg[i];
    fl=0;merge_sort(1,ntot);
    for (i=1;i<=ntot;i++) neg[i]=res[i];
        rtot=0;
        for (i=0;i<=m;i+=2)
        {
            if (ptot<m-i || ntot<i) continue;
            Getpos(m-i,i);
        }
        if (rtot>=k)
        {
            fl=0;merge_sort(1,rtot);
            res[k].print();
            return 0;
        }
        k-=rtot;
        rtot=0;reverse(pos+1,pos+ptot+1);reverse(neg+1,neg+ntot+1);
        for (i=1;i<=m;i+=2)
        {
            if (ptot<m-i || ntot<i) continue;
            Getneg(m-i,i);
        }
        fl=1;merge_sort(1,rtot);
        printf("-");res[k].print();
    return 0;
}
内容概要:该PPT详细介绍了企业架构设计的方法论,涵盖业务架构、数据架构、应用架构和技术架构四大核心模块。首先分析了企业架构现状,包括业务、数据、应用和技术四大架构的内容和关系,明确了企业架构设计的重要性。接着,阐述了新版企业架构总体框架(CSG-EAF 2.0)的形成过程,强调其融合了传统架构设计(TOGAF)和领域驱动设计(DDD)的优势,以适应数字化转型需求。业务架构部分通过梳理企业级和专业级价值流,细化业务能力、流程和对象,确保业务战略的有效落地。数据架构部分则遵循五大原则,确保数据的准确、一致和高效使用。应用架构方面,提出了分层解耦和服务化的设计原则,以提高灵活性和响应速度。最后,技术架构部分围绕技术框架、组件、平台和部署节点进行了详细设计,确保技术架构的稳定性和扩展性。 适合人群:适用于具有一定企业架构设计经验的IT架构师、项目经理和业务分析师,特别是那些希望深入了解如何将企业架构设计与数字化转型相结合的专业人士。 使用场景及目标:①帮助企业和组织梳理业务流程,优化业务能力,实现战略目标;②指导数据管理和应用开发,确保数据的一致性和应用的高效性;③为技术选型和系统部署提供科学依据,确保技术架构的稳定性和扩展性。 阅读建议:此资源内容详尽,涵盖企业架构设计的各个方面。建议读者在学习过程中,结合实际案例进行理解和实践,重点关注各架构模块之间的关联和协同,以便更好地应用于实际工作中。
资 源 简 介 独立分量分析(Independent Component Analysis,简称ICA)是近二十年来逐渐发展起来的一种盲信号分离方法。它是一种统计方法,其目的是从由传感器收集到的混合信号中分离相互独立的源信号,使得这些分离出来的源信号之间尽可能独立。它在语音识别、电信和医学信号处理等信号处理方面有着广泛的应用,目前已成为盲信号处理,人工神经网络等研究领域中的一个研究热点。本文简要的阐述了ICA的发展、应用和现状,详细地论述了ICA的原理及实现过程,系统地介绍了目前几种主要ICA算法以及它们之间的内在联系, 详 情 说 明 独立分量分析(Independent Component Analysis,简称ICA)是近二十年来逐渐发展起来的一种盲信号分离方法。它是一种统计方法,其目的是从由传感器收集到的混合信号中分离相互独立的源信号,使得这些分离出来的源信号之间尽可能独立。它在语音识别、电信和医学信号处理等信号处理方面有着广泛的应用,目前已成为盲信号处理,人工神经网络等研究领域中的一个研究热点。 本文简要的阐述了ICA的发展、应用和现状,详细地论述了ICA的原理及实现过程,系统地介绍了目前几种主要ICA算法以及它们之间的内在联系,在此基础上重点分析了一种快速ICA实现算法一FastICA。物质的非线性荧光谱信号可以看成是由多个相互独立的源信号组合成的混合信号,而这些独立的源信号可以看成是光谱的特征信号。为了更好的了解光谱信号的特征,本文利用独立分量分析的思想和方法,提出了利用FastICA算法提取光谱信号的特征的方案,并进行了详细的仿真实验。 此外,我们还进行了进一步的研究,探索了其他可能的ICA应用领域,如音乐信号处理、图像处理以及金融数据分析等。通过在这些领域中的实验和应用,我们发现ICA在提取信号特征、降噪和信号分离等方面具有广泛的潜力和应用前景。
标题Spring框架在大型超市前后台系统中的应用研究AI更换标题第1章引言介绍研究背景、意义,分析国内外在该领域的研究现状,并概述论文的研究方法和创新点。1.1研究背景与意义阐述Spring框架在大型超市前后台系统中的应用背景及其实际意义。1.2国内外研究现状分析国内外关于Spring框架在大型超市前后台系统中的应用研究现状。1.3研究方法与创新点介绍论文的研究方法,并突出论文的创新之处。第2章Spring框架及相关技术概述对Spring框架进行简要介绍,包括其核心特性和相关技术。2.1Spring框架简介概述Spring框架的基本概念、主要特点和优势。2.2Spring框架的核心组件详细介绍Spring框架的核心组件,如IoC容器、AOP等。2.3与Spring框架相关的技术阐述与Spring框架紧密相关的技术,如Spring MVC、Spring Data等。第3章大型超市前后台系统需求分析对大型超市前后台系统的需求进行详细分析,为后续系统设计奠定基础。3.1前台系统需求分析分析前台系统的功能需求,如商品展示、购物车管理等。3.2后台系统需求分析分析后台系统的功能需求,如商品管理、订单处理等。3.3非功能性需求分析讨论系统的性能、安全性等非功能性需求。第4章基于Spring框架的大型超市前后台系统设计根据需求分析结果,设计基于Spring框架的大型超市前后台系统。4.1系统架构设计设计系统的整体架构,包括前后台系统的交互方式、数据流向等。4.2数据库设计设计系统的数据库结构,包括表结构、数据关系等。4.3界面设计设计前后台系统的用户界面,确保用户友好性和交互性。第5章系统实现与测试详细阐述系统的实现过程,并对系统进行测试以验证其功能和性能。5.1系统实现按照系统设计,实现前后台系统的各个功能模块。5.2系统测试对系统进行功能测试、性能测试等,确保系统满足需求并具有稳定性
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值