zoukankan      html  css  js  c++  java
  • 2020 camp day0 -F

    题面

    7-6 1F. 乘法

    给出一个长度为 n 的数列 和一个长度为 m 的数列 ,可以构造得到一个 n×m 的矩阵 C,其中 C​i,j​​=A​i​​×B​j​​。

    给出整数 K,你需要求出 C 中第 K 大的数的值。

    输入格式:

    第一行输入三个整数 ,。

    第二行输入 n 个空格隔开的整数 ,

    第三行输入 m 个空格隔开的整数 ,

    输出格式

    输出一行一个整数,表示矩阵中的第 K 大的数的值。

    输入样例:

    3 3 3
    2 3 4
    4 5 6
    
     

    输出样例:

    18

    作者: 2020,Winter,Day1
    单位: 东北大学秦皇岛分校
    时间限制: 1000 ms
    内存限制: 256 MB
    代码长度限制: 16 KB
     

    题解

    对于答案 二分即可,差找比这个值大的输有几个,相等的有几个,然后就可以check这个值是否则正确。

    关键在于怎么区遍历整个矩阵查找。

    要是只有正数要好做许多。

    对于全是正数而言:

    直接 A * B复杂度直接boom,可以先排序,外循环从小到大,内循环从大到小,保证内循环使得乘积不断变小,记下满足条件的内循环时 j 的值,然后++i,乘积变大,但保证与对于之前循环过的 j 位置的数相乘乘积大于阈值,

    这样就减少了内层循环,使得 i, j实际一个变大,一个表变小,实现 复杂度 A + B 而不是 A * B。

    现在再考虑正负,分情况讨论即可,只要保证两个循环不会回退,实现 复杂度相加即可,分成两种就行,我弄麻烦了,分成了 A非负、A负、B非负、B负四部分,相对麻烦一这些。

    代码如下

    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <cmath>
    
    #define RE register
    #define FOR(i,a,b) for(RE int i=a;i<=b;++i)
    #define ROF(i,a,b) for(RE int i=a;i>=b;--i)
    #define sc(n) scanf("%d",&n)
    #define ll long long
    
    using namespace std;
    
    const int MAXN = 100010;
    
    int a[MAXN], b[MAXN], tota, totb;
    int x[MAXN], y[MAXN], totx, toty;
    int T, n, m;
    ll k;
    
    int check(long long val)
    {
        ll cnt = 0, tot = 0;
        for (int i = 0, j = totb - 1; i < tota && cnt < k; ++i)
        {
            while (j >= 0 && 1ll * a[i] * b[j] > val) --j;
            cnt += (1ll * totb - j - 1);
            int jj = j;
            while (jj >= 0 && 1ll * a[i] * b[jj] == val) --jj, ++tot;
        }
        for (int i = tota - 1, j = toty - 1; i >= 0 && cnt < k; --i)
        {
            while (j >= 0 && 1ll * a[i] * y[j] > val) --j;
            cnt += (1ll * toty - j - 1);
            int jj = j;
            while (jj >= 0 && 1ll * a[i] * y[jj] == val) --jj, ++tot;
        }
        for (int i = totb - 1, j = totx - 1; i >= 0 && cnt < k; --i)
        {
            while (j >= 0 && 1ll * b[i] * x[j] > val) --j;
            cnt += (1ll * totx - j - 1);
            int jj = j;
            while (jj >= 0 && 1ll * b[i] * x[jj] == val) --jj, ++tot;
        }
        for (int i = totx - 1, j = 0; i >= 0 && cnt < k; --i)
        {
            while (j < toty && 1ll * x[i] * y[j] > val) ++j;
            cnt += j;
            int jj = j;
            while (jj < toty && 1ll * x[i] * y[jj] == val) ++jj, ++tot;
        }
        if (cnt < k && cnt + tot >= k)return -1;
        if (cnt < k) return 1;
        return 0;
    }
    
    ll solve()//二分查找第k大的数
    {
        ll l = 1e13, r = -1e13;
        if (totx && totb) l = min(l, 1ll * x[0] * b[totb - 1]);
        if (toty && tota) l = min(l, 1ll * y[0] * a[tota - 1]);
        if (totx && toty) l = min(l, 1ll * y[toty - 1] * x[totx - 1]);
        if (tota && totb) l = min(l, 1ll * a[0] * b[0]);
    
        if (totx && totb) r = max(r, 1ll * x[totx - 1] * b[0]);
        if (toty && tota) r = max(r, 1ll * y[toty - 1] * a[0]);
        if (totx && toty) r = max(r, 1ll * y[0] * x[0]);
        if (tota && totb) r = max(r, 1ll * a[tota - 1] * b[totb - 1]);
        while (l < r)
        {
            ll mid = (l + r) >> 1;
            int ans = check(mid);
            if (ans == -1)return mid;
            if (ans) r = mid;
            else l = mid + 1;
        }
        return l;
    }
    
    int main()
    {
        scanf("%d%d%lld", &n, &m, &k);
        for (int i = 0; i < n; ++i)
        {
            sc(T);
            if (T >= 0)a[tota++] = T;
            else x[totx++] = T;
        }
        for (int i = 0; i < m; ++i)
        {
            sc(T);
            if (T >= 0)b[totb++] = T;
            else y[toty++] = T;
        }
        sort(a, a + tota);
        sort(x, x + totx);
        sort(b, b + totb);
        sort(y, y + toty);
        printf("%lld
    ", solve());
        return 0;
    }
    

      

  • 相关阅读:
    修改Nginx的header伪装服务器
    解除与设置计算机锁定
    Adobe flash cs5 的Java运行时环境初始化错误 完美解决方法
    js正则表达式教程
    Eclipse窗口显示:独立、嵌入式
    [置顶] wzplayer for android NEON版本(添加插图)
    买了一块s5pv210 的开发板
    [置顶] android player ,wzplayer for android NEON版本(添加插图)
    make 输出 log 文件
    android player ,wzplayer for android NEON版本(添加插图)
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/12194261.html
Copyright © 2011-2022 走看看