YACS 两数之积 题解
作者:互联网
分别考虑原数组 $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