• Codeforces 1288D


    题目大意:

    给定n个序列,每个序列元素个数严格相等于m

    你需要找到两个序列a[i]和a[j],使其每个对应位置的元素取大后得到b序列  b[k]=max(a[i][k],a[j][k])

    且让b序列中的最小值最大

    i可以等于j

    解题思路:

    二分假设这个b序列的最小值的值x

    将a序列转化成01构成的二进制串存在数组b中

    0表示当前位置的值<x

    1表示当前位置的值>=x

    每次便最多可以得到3e5个字符

    双层循环i,j从0到255(最大)

    只要满足b[i]存在且b[j]存在且b[i]和b[j]按位取或后得到的结果每一位都是1(即a[i]和a[j]这两个数列按照题目所述方式得到的最小值比当前枚举的x大,此时说明二分的x是可行的,返回true)

    如果找不到,返回false,说明x二分得太大了

    二分的过程中在返回true之前就可以记录一下当前枚举到的i和j

    总时间复杂度最坏情况为为O(log1e9 * (3e5+255^2)) 约为O(1e7)满足题意

    #include<bits/stdc++.h>
    using namespace std;
    int a[300050][10],b[300],n,m,ci,cj,cpd=0;
    bool prim(int x){
        int i,j,d;
        memset(b,0,sizeof b);
        for(i=1;i<=n;i++){
            d=0;
            for(j=0;j<m;j++)
                if(a[i][j]>=x)
                    d|=(1<<j);
            b[d]=i;
        }
        for(i=0;i<=cpd;i++)
            for(j=0;j<=cpd;j++)
                if(b[i]&&b[j]&&((i|j)==cpd)){
                    ci=b[i];
                    cj=b[j];
                    return true;
                }
        return false;
    }
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        int i,j,l=0,r=1e9,mid;
        cin>>n>>m;
        if(n==1){
            cout<<"1 1
    ";
            return 0;
        }
        for(j=0;j<m;j++)
            cpd|=(1<<j);
        for(i=1;i<=n;i++)
            for(j=0;j<m;j++)
                cin>>a[i][j];
        while(l<=r){
            mid=(l+r)>>1;
            if(prim(mid))
                l=mid+1;
            else
                r=mid-1;
        }
        prim(r);
        cout<<ci<<' '<<cj<<endl;
        
        return 0;
    }
  • 相关阅读:
    牢固你的人际关系三十六计
    Google 将携手大众,开发新一代汽车导航系统
    C++图书热点观察[转]
    Qt程序http报错 TLS initialization failed
    基于kinova jaco2机械臂的仿真模拟
    IfcBuild2Axes
    threejs绘制多边形2
    QAction
    java Math.pow
    yolov5模型地址
  • 原文地址:https://www.cnblogs.com/stelayuri/p/12222939.html
Copyright © 2020-2023  润新知