• POJ 3419 Difference Is Beautiful(RMQ变形)


    题意:N个数,M个询问,每个询问为一个区间,求区间最长连续子序列,要求每个数都不同(perfect sequence,简称PS)。

    题解:很容易求出以每个数为结尾的ps,也就是求区间的最大值。有一个不同就是长度可能会超出询问范围,所以先对PS的首位置二分,然后RMQ。注意一点,序列有可能出现负数,所以先加最大值变为正数。其实也不算变形,挺裸的……

    这题卡线段树,然而我只会线段树,心塞……

    代码(树状数组):

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 2000005;
    
    int a[N], pos[N], len[N], nt[N];
    
    #define lowbit(x) ((x)&(-x))
    int idx[N];
    
    void init(int n)
    {
        for(int i=1;i<=n;i++) {
            idx[i] = len[i];
            for(int j=1;j<lowbit(i);j<<=1){
                idx[i]=max(idx[i],idx[i-j]);
            }
        }
    }
    
    int query(int l, int r)
    {
        int ans=len[r];
        while(true) {
            ans=max(ans,len[r]);
            if(r==l) break;
            for(r-=1;r-l>=lowbit(r);r-=lowbit(r)){
                ans=max(ans,idx[r]);
            }
        }
        return ans;
    }
    
    int main()
    {
        int n, m;
        while (~scanf("%d%d", &n, &m)) {
            for (int i = 1; i <= n; ++i) {
                scanf("%d", &a[i]);
                a[i] += 1000000;
            }
            memset(pos, 0, sizeof pos);
            nt[0] = 1;
            for (int i = 1; i <= n; ++i) {
                nt[i] = max(nt[i-1], pos[a[i]]+1);//nt[i]以i为结尾的最长子序列的首端
                len[i] = i-nt[i]+1;
                pos[a[i]] = i;
            }
            init(n);
    
            while (m--) {
                int l, r;
                scanf("%d%d", &l, &r); l++, r++;
                int p = upper_bound(nt+1, nt+1+n, l) - nt;
                int ans = 0;
                if (p > r) {
                    printf("%d
    ", r-l+1);
                    continue;
                }
                if (p > l) ans = p-l;
                ans = max(ans, query(p, r));
                printf("%d
    ", ans);
            }
        }
        return 0;
    }

    代码(ST算法):

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 2000005;
    
    int a[N], pos[N], len[N], nt[N];
    int f[N][20];
    
    void init(int n)
    {
        // f[i,j]表示[i,i+2^j-1]区间最大值
        // f[i,j]=max(d[i,j-1], d[i+2^(j-1),j-1])
        for (int i = 1; i <= n; ++i) f[i][0] = len[i];
        for (int j = 1; (1<<j) <= n; ++j)
            for (int i = 1; i+j-1 <= n; ++i)
                f[i][j] = max(f[i][j-1], f[i+(1<<j-1)][j-1]);
    }
    
    int query(int l, int r)
    {
        int k = 0;
        while ((1<<k+1 <= r-l+1)) ++k;
        return max(f[l][k], f[r-(1<<k)+1][k]);
    }
    
    
    int main()
    {
        int n, m;
        while (~scanf("%d%d", &n, &m)) {
            for (int i = 1; i <= n; ++i) {
                scanf("%d", &a[i]);
                a[i] += 1000000;
            }
            memset(pos, 0, sizeof pos);
            nt[0] = 1;
            for (int i = 1; i <= n; ++i) {
                nt[i] = max(nt[i-1], pos[a[i]]+1);//nt[i]以i为结尾的最长子序列的首端
                len[i] = i-nt[i]+1;
                pos[a[i]] = i;
            }
            init(n);
    
            while (m--) {
                int l, r;
                scanf("%d%d", &l, &r); l++, r++;
                int p = upper_bound(nt+1, nt+1+n, l) - nt;
                int ans = 0;
                if (p > r) {
                    printf("%d
    ", r-l+1);
                    continue;
                }
                if (p > l) ans = p-l;
                ans = max(ans, query(p, r));
                printf("%d
    ", ans);
            }
        }
        return 0;
    }

    还有一种网上流传的算法,类似kmp。想法很巧妙,但是最坏复杂度貌似是O(n^2),不过也能A这道题。而且速度不必上面慢。数据水吧~

    nt[i]记录想要字串中含有a[(i+1)-pos[i+1]]的最大位置。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    using namespace std;
    const int N = 2000005;
    
    int a[N], pos[N], len[N], nt[N];
    
    int main()
    {
        int n, m;
        while (~scanf("%d%d", &n, &m)) {
            for (int i = 1; i <= n; ++i) {
                scanf("%d", a+i);
                a[i] += 1000000;
            }
            memset(pos, 0, sizeof pos);
            len[0] = 0; nt[0] = 0;
            for (int i = 1; i <= n; ++i) {
                if (len[i-1]+1 <= i-pos[a[i]]) {
                    len[i] = len[i-1]+1;
                    nt[i] = nt[i-1];
                } else {
                    len[i] = i-pos[a[i]];
                    nt[i] = i-1;
                }
                pos[ a[i] ] = i;
                //printf("%d %d %d
    ", len[i], nt[i], pos[a[i]]);
            }
            while (m--) {
                int l, r;
                scanf("%d%d", &l, &r); l++, r++;
                int res = len[r];
                if (res >= r-l+1) {
                    printf("%d
    ", r-l+1);
                    continue;
                }
                while (nt[r] > 0) {
                    r = nt[r];
                    res = max(res, min(len[r], r-l+1));
                    if (res >= r-l+1) {
                        break;
                    }
                }
                printf("%d
    ", res);
            }
        }
        return 0;
    }
  • 相关阅读:
    flask-login
    python3安装scrapy框架
    Redis--对象共享(整数型字符串)
    Redis--对象(type、encoding、ptr、lru、refcount)
    Redis--内存回收(引用计数法)
    Redis--跳跃表
    Redis--压缩列表(节约内存,连锁更新)
    Redis--整数集合(升降级)
    Redis--Rehash(h[0],h[1],rehashIdx, 渐进式)
    Redis--解决Hash表键冲突(单向链表next指针,表头)
  • 原文地址:https://www.cnblogs.com/wenruo/p/5562329.html
Copyright © 2020-2023  润新知