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; }