zoukankan      html  css  js  c++  java
  • 启发式分治入门 Non-boring sequences UVA

    参考自:https://blog.csdn.net/XY20130630/article/details/50635756

    题意:一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字,
    即每个子序列里至少存在一个数字只出现一次。
    给定一个整数序列,请你判断它是不是不无聊的。

    分析:预处理每个元素上一次出现位置和下一个出现位置,
      我们发现对于一个子序列[L,R]来说,
      如果存在pre[i]<L&&nxt[i]>R那么这个子序列一定是满足条件的,
      否则就不满足,那么我们分治处理这个问题,
      从两边往中间寻找这个i,那么每次拆开的复杂度就是拆成的两个序列中较小的一个,
      所以这是一个逆启发式合并的过程,复杂度O(nlogn)

    一、在区间[l,r]找到一个只出现一次的元素P(如果不存在,那么序列无聊)
    二、递归处理区间[l,p−1]和区间[p+1,r]

    关键在于如何找到一个只出现一次的元素。

    首先,我们得知道如何判断一个元素是不是只出现一次。
    我们可以用STL中的map记录与当前元素值相同的上一个元素(下一个元素)的位置,然后滚动更新即可。
    因为map的所有操作都是O(logn)的,所以预处理的时间复杂度为O(nlogn)

    所以,我们就可以用O(1)的时间判断出一个元素是不是只出现一次了。

    若从左到右扫描整个序列,那么最坏情况,这个元素在序列的最右边,则
    T(n)=T(n−1)+O(n)≥T(n2)=O(n2)

    根据二分法一般是尽量分成两个数量尽量接近的数列,我们可以考虑从两边往中间找。(这就是启发式)
    此时,最坏情况为这个元素在序列的正中间,则
    T(n)=2T(n/2)+O(n),解得T(n)=O(nlogn)

    所以算法的总时间复杂度为O(nlogn)

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <map>
    using namespace std;
    
    const int maxn = 2e5+5;
    int n;
    int pre[maxn],nxt[maxn],a[maxn];
    map<int,int> mp;
    
    bool check(int L,int R){                   //先预处理pre,nxt
        if(L>=R) return true;
        int l=L,r=R;
        for(int i=L; i<=R; i++){               //后从两边往中间判断,就会玄学降低复杂度,目的在于找点
            if(i&1){
                if( pre[l]<L && nxt[l]>R ){    //满足pre[i]<L&&nxt[i]>R 则这个点符合条件
                    return check(L,l-1) && check(l+1,R);  //就再判断剩下的子串
                }
                l++;
            }
            else{
                if( pre[r]<L && nxt[r]>R){
                    return check(L,r-1) && check(r+1,R);
                }
                r--;
            }
        }
        return false;
    }
    
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            for(int i=1; i<=n; i++){
                scanf("%d",a+i);
            }
            mp.clear();
            for(int i=1; i<=n; i++){
                pre[i] = mp[ a[i] ];
                nxt[ mp[a[i]] ] = i;
                mp[ a[i] ] = i;
            }
            for(int i=1; i<=n; i++){
                nxt[ mp[a[i]] ] = n+1;
            }
            if(check(1,n)) puts("non-boring");
            else puts("boring");
        }
    }
  • 相关阅读:
    POJ 1548 Robots(最小路径覆盖)
    <html>
    站点开发-日志-1
    JSP入门实战下
    rancher官方资源
    window10死机
    window10桌面图标空白
    sentry使用docker-compose部署
    docker下一步步部署sentry
    docker-compose编排服务
  • 原文地址:https://www.cnblogs.com/-Zzz-/p/11525299.html
Copyright © 2011-2022 走看看