HDU 5172

超内存了,呃。。。不知道如何优化了。

首先要判断区间的和是否和1~n的和相等。

再个,记录下每个数字前一次出现的位置,求这些位置的最大值,如果小于左端点,则表示有这样的一个序列。

呃~~~第二个条件当时曾有想过,但认为要在O(1)时间内得出不可能,后来才知道,还有ST算法啊。。。。不让熟练啊。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define LL __int64

using namespace std;
const int MAX=1000002;
int num[MAX],pre[MAX];
double sum[MAX];
int dp[MAX][21];

void ST(int n){ 
    int i, j, k, m;
    k = (int) (log((double)n) / log(2.0)); 
    for(i = 1; i <= n; i++) {
        dp[i][0] = num[i]; 
    }
    for(j = 1; j <= k; j++) { 
        for(i = 1; i + (1 << j) - 1 <= n; i++)   {
            m = i + (1 << (j - 1)); 
            dp[i][j] = max(dp[i][j-1], dp[m][j-1]);
        }
    }
}
int rmq(int i, int j) { 
     int k = (int)(log(double(j-i+1)) / log(2.0)), t1; 
     t1 =max(dp[i][k], dp[j - (1<<k) + 1][k]);
     return t1;
}

int main(){
	int n,m,tmp,l,r,i; double tsum;
	while(scanf("%d%d",&n,&m)!=EOF){
		sum[0]=0;
		memset(pre,0,sizeof(pre));
		for(i=1;i<=n;i++){
			scanf("%d",&tmp);
			sum[i]=sum[i-1]+tmp;
			num[i]=pre[tmp];
			pre[tmp]=i;
		}
		ST(n);
		while(m--){
			scanf("%d%d",&l,&r);
			tsum=(r-l+2)*(r-l+1)*1.0/2.0;
			if(tsum!=sum[r]-sum[l-1]){
				puts("NO");
				continue;
			}
			if(rmq(l,r)<l){
				puts("YES");
			}
			else puts("NO");
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/jie-dcai/p/4280097.html