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\n", r-l+1);
                continue;
            }
            if (p > l) ans = p-l;
            ans = max(ans, query(p, r));
            printf("%d\n", 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\n", r-l+1);
                continue;
            }
            if (p > l) ans = p-l;
            ans = max(ans, query(p, r));
            printf("%d\n", 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\n", 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\n", 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\n", res);
        }
    }
    return 0;
}
时间: 2024-08-05 16:23:03

POJ 3419 Difference Is Beautiful(RMQ变形)的相关文章

POJ 3419 Difference Is Beautiful(RMQ+二分 或者 模拟)

Difference Is Beautiful Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Submit Status Practice POJ 3419 Description Mr. Flower's business is growing much faster than originally planned. He has now become the CEO of a world-

POJ 3419 Difference Is Beautiful

先处理出每一个i位置向左最远能到达的位置L[i].每一次询问,要找到L,R区间中的p位置,p位置左边的L[i]都是小于L的,p位置开始,到R位置,L[i]都大于等于L,对于前者,最大值为p-L,后者求一个区间最大值即可. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include&

POJ 3419 (rmq)

这道题是rmq,再加上一个解决溢出. 刚开始我也想过用rmq,虽然不知道它叫什么,但是我知道应该这样做.可是后来没想到这道题的特殊性,也就是解决溢出的方法,就放弃了. rmq可以用线段树,也可以用dp.  这道题都可以过的,而且线段树要快一些. #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; #define m

poj 3264 区间最大最小值 RMQ问题之Sparse_Table算法

Balanced Lineup Time Limit: 5000 MS Memory Limit: 0 KB 64-bit integer IO format: %I64d , %I64u Java class name: Main [Submit] [Status] [Discuss] Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order

POJ 1007 Difference Between Primes(线性筛法求N以内的素数表)

Difference Between Primes Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description All you know Goldbach conjecture.That is to say, Every even integer greater than 2 can be expressed as the sum of two primes. Today, sk

POJ 1797 Heavy Transportation (最短路变形)

Heavy Transportation Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 20364   Accepted: 5401 Description Background Hugo Heavy is happy. After the breakdown of the Cargolifter project he can now expand business. But he needs a clever man

POJ 2019 Cornfields 二维RMQ

题目来源:POJ 2019 Cornfields 题意:求正方形二维区间最大最小值的差 思路:直接二维ST搞 试模版而已 #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int maxn = 255; int dp[maxn][maxn][8][8]; int dp2[maxn][maxn][8][8]; int a[maxn][maxn]; int n

poj 2368 巴什博奕变形

http://poj.org/problem?id=2368 巴什博奕看这里http://blog.csdn.net/u011026968/article/details/38434777 这题比较无聊的地方是,卡时间,O(n)算法会超时 #include<iostream> #include<cstdlib> #include<stdio.h> #include<algorithm> using namespace std; int a[1010]; in

POJ 3264:Balanced Lineup Rmq模板

Balanced Lineup 题目链接: http://poj.org/problem?id=3264 题意: 求区间最大值和最小值的差 题解: Rmq模板题 代码 #include<stdio.h> #include<math.h> const int N=5e4+1; int dpmax[N][17]; int dpmin[N][17]; int mmax(int x,int y) { return x>y?x:y; } int mmin(int x,int y) {