• Educational Codeforces Round 80 (Div. 2)


    1288D. Minimax Problem (二分+状态压缩)

    题意&&思路

    题意:
    给出 n 个长度为 m 的序列(1 ≤ n ≤ 3*1e5, 1≤ m ≤8 ),对于序列中的每一个元素 a,(0≤a≤1e9)
    现在你要求出,对于所有任意两行序列为一组(或则自己本身成为一组),进行(两个序列的同一个位置取最大值放到新序列中)操作形成新的序列,再从新的序列中选取最小值作为ans,最后要对所有可能组成的ans中输出最大的ans.
    思路:
    说实话没有想到用二分加二进制压缩表示来求解。二分倒是可以想到,毕竟正向 把两两所有枚举都是 O( n^2 )了,所以就容易想着反向去求解答案。
    题解给的是:二分去选取一个数(作为假设的最终答案),把 序列中比这个数小的 记为0,大于等于这个数记为1. 最后就可以得到一个(0~2^m-1)范围类的二进制数。
    也就是说本来我们需要 O( n^2 )去匹配的,现在状态压缩用二进制去等同表示后只需要O( m^2 )去验证,而m的范围为 1≤ m ≤8,所以就大大降低了复杂度。
    而验证该数 X 是答案的规则即是,是否存在两个二进制数,最后 或 的结果为 全1 .(因为由于取得是最大序列的最小值,如果两个序列或为1,那么这两个序列中必然能够选出一个大于等于X 的序列)
    例如:下面两个序列红色表示对应位置的值更大(假设选取的 x 能作为答案)。
    a b  c  d  e   ->  1 0 1 0 1
    A B C  D  E   -> 0 1 1 1 0
    View Code

    Code:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int inf=0x3f3f3f3f;
    const int MAXN=3e5+10;
    int n,m,a[MAXN][10],mark[300],pos1,pos2,ans1,ans2;
    
    //bitmasks 
    bool check(int x){
        pos1 = 0,pos2 = 0;
        memset(mark,0,sizeof(mark));
        for(int i=1;i<=n;i++){
            int tot = 0;
            for(int j=0;j<m;j++){
                if(x<=a[i][j]) tot += (1<<j); 
            }
            mark[tot] = i;
        }
        for(int i=1;i<= (1<<m)-1;i++){
            for(int j=i; j<= (1<<m)-1;j++){
                if((i|j)== (1<<m)-1&&mark[i]&&mark[j]) {
                    pos1 = mark[i];
                    pos2 = mark[j];    
                }
            }
        }
        return pos1&&pos2;
    }
    
    //binary search
    int BS(int l,int r){ 
        int mid;
        while(l<=r){
            mid = (l+r)>>1;
            if(check(mid)) l = mid+1,ans1 = pos1,ans2 = pos2;
            else r = mid-1;
        }
        return l;
    } 
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=0;j<m;j++)
                scanf("%d",&a[i][j]);
        int l=0,r=1e9;
        l = BS(l,r);
        printf("%d %d
    ",ans1,ans2);
        return 0;
    }
    View Code

    1288E. Messenger Simulator (树状数组)

    题意&&思路

    题意:定义初始序列为给定长度为N的序列 1,2,3...,N ,再给出一个长为M的序列(1≤N,M≤3e5) ,表示对应操作。模拟操作为对应值位置提到序列的最前面,比如原序列为1 2 3 4 5,此时给出操作3,即变为
    3 1 2 4 5. 最后输出对应从 1到N 每个数在整个操作中的最小位置和最大位置
    思路:
    要统计一个数的之前有多少个数出现,一般的想法便是遍历从1到该数的位置。如果我们用一个vis[] 表示某个位置上是否有值,pos[value] 记录每个值的当前位置,那么只需要求从 1到pos[value]的前缀和为多少即可。所以此时使用树状数组来降低计算前缀和的复杂度到 logn . (类似操作可以参考一下:树状数组对逆序数的计算:冒泡排序的交换次数 (树状数组) )
    View Code

    Code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring> 
    typedef long long ll;
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int maxn = 3e5+5;
    const int maxm = 5e5+5;
    int t[maxn<<1];//树状数组要开两倍,由于N+M的范围
    int minp[maxn];
    int maxp[maxn];
    int pos[maxn];
    int N,M,K;
    int lowbit(int x){
        return x&-x;
    }
    void add(int x,int k){
        while(x<=N+M){
            t[x] += k;
            x += lowbit(x);
        }
    }
    int ask(int x){
        int ans = 0;
        while(x>0){
            ans += t[x];
            x -= lowbit(x);
        }
        return ans;
    }
    
    int main(){
        cin>>N>>M;
        memset(t,0,sizeof(t));
        for(int i=1;i<=N;i++) {
            pos[i]=i+M;//初始位置
            minp[i] = maxp[i] = i;
            add(pos[i],1);
        }
        //动态查询 
        for(int i=1;i<=M;i++){
            int temp;
            cin>>temp;
            minp[temp] = 1;//更新最小位置 
            maxp[temp] = max(maxp[temp],ask(pos[temp])); 
            add(pos[temp],-1);//删除原位置 
            pos[temp] = M-i+1;//更新该数最新位置 
            add(M-i+1,1);//更新位置 
        }
        for(int i=1;i<=N;i++) maxp[i] = max(maxp[i],ask(pos[i]));//最后再更新一次 
        for(int i=1;i<=N;i++){
            cout<<minp[i]<<" "<<maxp[i]<<endl;
        }
    } 
    View Code
  • 相关阅读:
    java作用域public ,private ,protected 及不写时的区别
    Android开发环境部署
    java的WebService实践(cxf)
    Servlet小试
    XML内容作为String字符串读取报错
    myeclipse安装svn插件的多种方式
    一个简单的SpringMVC3 程序
    VS2010调试生成的文件
    双系统启动项修复
    安装服务命令
  • 原文地址:https://www.cnblogs.com/Tianwell/p/12231753.html
Copyright © 2020-2023  润新知