ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

YACS 两数之积 题解

2022-08-04 18:34:20  阅读:163  来源: 互联网

标签:YACS bf bz 题解 ll cnt2 cnt1 x1 两数


link

 

分别考虑原数组 $a[]$ 中所有的正数,负数以及 0 的数量:

设 $a[]$ 中正数的数量为 $cnt1$ 个,把 $a[]$ 中所有正数保存在 $bz[]$ 数组中,

负数数量为 $cnt2$ 个,保存在 $bf[]$ 数组中,

0 的数量为 $cnt0$ 个。

----------------------------------

设 $x1$, $x0$, $x2$ 分别为两两相乘之后新生成的 $b$ 序列中所有正数,0 ,负数的个数,则:


$$x1=cnt1*(cnt1-1)/2+cnt2*(cnt2-1)/2$$

$$x0=cnt0*(n-1)$$

$$x2=cnt1*cnt2$$

-----------------------------------

讨论 t 的大小:

1. 若 $t≤x1$ ,则这个第 $t$ 大数一定是在 $b$ 序列中所有的正数中产生的,

把  $bz[]$ 数组升序排序,$bf[]$ 数组先全部变为正数 ( 两两相乘之后一定为正数,先把每个数变成正数方便计算),然后升序排序。

二分答案找到 $bz[]$ 所有数字和 $bf[]$ 数组中所有数字两两相乘之后的第 $t$ 大。

2. 若 $x1<t≤x1+x0$,则这个第 $t$ 大数就是 0 。

3. 若 $t>x1+x0$  则这个第 $t$ 大数一定是在 $x2$ 个负数中产生的,

问题转化为找到 $bz[]$ 数组中所有数字和 $bf[]$ 数组中所有数字两两相乘后的第 $t-(x1+x0)$ 大

同样通过二分答案找到这个第 $t-(x1+x0)$ 大数字, 即是原问题所有数字中的第 $t$ 大。

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;

const int maxn = 1e7+10;

ll bz[maxn]= {0}, bf[maxn]= {0};
ll x=0, n=0, t=0;
ll cnt1=0, cnt0=0, cnt2=0;
ll x1=0, x0=0, x2=0;
ll l=0 , r=0;

namespace IO_ReadWrite {
    #define getchar()(p1==p2&&(p2=(p1=_buf)+fread(_buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    char _buf[1<<21],*p1=_buf,*p2=_buf;
    char ch;bool ff;
    template <typename T>
    inline void read(T &x){
        x=0;ff=false;ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')ff=true;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        if(ff)x=~x+1;
        return;
    }
    template <typename T>
    inline void write(T x){
        if(x<0)putchar('-'),x=~x+1;
        if(x>9)write(x/10);
        putchar(x%10+'0');
        return;
    }
    inline void ReadChar(char &c){
        do{c=getchar();}while(ch<'0'||ch>'9');return;
    }
    template <typename T>
    inline void writeln(T x){write(x);putchar('\n');return;}
}
using namespace IO_ReadWrite;

bool judge(ll num) {
    ll tmp = 0;
    for (int i = 0; i < cnt1; i++) {
        ll p = upper_bound(bz, bz+cnt1, num/bz[i])-bz;
        if (p > i) tmp += cnt1-p;
        else tmp += cnt1-i-1;
    }
    for (int i = 0; i < cnt2; i++) {
        ll p = upper_bound(bf, bf+cnt2, num/bf[i])-bf;
        if (p > i) tmp += cnt2-p;
        else tmp += cnt2-i-1;
    }
    return tmp >= t;
}

bool check(ll num) {
    ll tmp = 0;
    for (int i = 0; i < cnt1; i++) {
        tmp += cnt2-(upper_bound(bf,bf+cnt2, floor((double)num/bz[i]))-bf);
    }
    return tmp >= t-(x1+x0);
}

int main() {
    read(n);read(t);
    for (int i = 0; i < n; i++) {
        read(x);
        if (x > 0) bz[cnt1++] = x;
        else if (x == 0) cnt0 ++;
        else bf[cnt2++] = x;
    }
    x1 = cnt1*(cnt1-1)/2+cnt2*(cnt2-1)/2;
    x0 = cnt0*(n-1);x2 = cnt1*cnt2;
    if (t <= x1) {
        for(int i=0; i<cnt2; i++)bf[i]*=-1;
        sort(bz,bz+cnt1);
        sort(bf,bf+cnt2);
        l = min(bz[0]*bz[1], bf[0]*bf[1]);
        r = max(bz[cnt1-1]*bz[cnt1-2], bf[cnt2-1]*bf[cnt2-2]);
        while (l <= r) {
            ll mid = (l+r)>>1;
            if (judge(mid))l = mid+1;
            else r = mid-1;
        }
        writeln(l);
    }
    else if (t > x1 && t <= x1+x0)putchar('0');
    else {
        sort(bz, bz+cnt1);
        sort(bf, bf+cnt2);
        l = bz[0]*bf[0];
        r = bz[cnt1-1]*bf[cnt2-1];
        while (l <= r) {
            ll mid = (l+r)/2;
            if (check(mid))l = mid+1;
            else r = mid-1;
        }
        writeln(l);
    }
    return 0;
}
View Code

 

标签:YACS,bf,bz,题解,ll,cnt2,cnt1,x1,两数
来源: https://www.cnblogs.com/wkh2008/p/16551554.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有