dutacm.club 1094: 等差区间(RMQ区间最大最小值,区间GCD)

Posted 贱人方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dutacm.club 1094: 等差区间(RMQ区间最大最小值,区间GCD)相关的知识,希望对你有一定的参考价值。

1094: 等差区间

Time Limit:5000/3000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:655   Accepted:54
[Submit][Status][Discuss]

Description

已知一个长度为 n

的数组 a[1],a[2],,a[n],我们进行 q 次询问,每次询问区间 a[l],a[l+1],,a[r?1],a[r]

,数字从小到大排列后,是否会形成等差数列。等差数列的定义为,数列相邻两项(后一项减去前一项)的差值相等。

Input

本题有多组输入数据。

每组输入数据第一行输入两个正整数 n

q。第二行输入 n 个正整数 a[1],a[2],,a[n]。最后输入 q 行,每行两个数字 l,r(1lrn),表示询问区间 a[l],,a[r]

1≤n,q≤105,1≤a[i]≤106

Output

对于每组询问输出一行,如果形成等差数列,输出“Yes ”,否则输出“No”(不含引号)。

Sample Input

5 5
3 1 5 2 4
1 3
4 5
1 4
3 4
2 2

Sample Output

Yes
Yes
No
Yes
Yes

HINT

【分析】

区间 [L,R] 内的数排序后构成等差数列可分两种情况 
1.公差为 0 
2.公差不为 0 ? 区间内无相同元素 且 相邻两项差构成的数列的GCD ×(R?L) = (区间最大值-区间最小值) 
所以RMQ查询区间最大值最小值以及(各个数的上一个相同数的下标的最大值)以及区间GCD
好强大的RMQ啊,打算明天自己裸敲一遍。。。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#define inf 0x3f3f3f3f
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int>pii;
const int N = 1e5+5;
const int M = 18;
int mn[N][M],mx[N][M],pre[N][M],gcd[N][M];
int mm[N],n,q;
int mat[N*10];
void init() {
    for(int j=1; j<=mm[n]; ++j) {
        for(int i=1; i+(1<<j)-1<=n; ++i) {
            mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
            mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
            pre[i][j]=max(pre[i][j-1],pre[i+(1<<(j-1))][j-1]);
            gcd[i][j]=__gcd(gcd[i][j-1],gcd[i+(1<<(j-1))][j-1]);
        }
    }
}
int getmx(int l,int r) {
    int k = mm[r-l+1];
    return max(mx[l][k],mx[r-(1<<k)+1][k]);
}
int getmn(int l,int r) {
    int k = mm[r-l+1];
    return min(mn[l][k],mn[r-(1<<k)+1][k]);
}
int getpre(int l,int r) {
    int k = mm[r-l+1];
    return max(pre[l][k],pre[r-(1<<k)+1][k]);
}
int getgcd(int l,int r) {
    int k = mm[r-l+1];
    return __gcd(gcd[l][k],gcd[r-(1<<k)+1][k]);
}
int read() {
    int x=0,f=1;
    char ch=getchar();
    while(ch<0||ch>9) {
        if(ch==-)f=-1;
        ch=getchar();
    }
    while(ch>=0&&ch<=9) {
        x=x*10+ch-0;
        ch=getchar();
    }
    return x*f;
}
int main() {
    mm[0]=-1;
    for(int i=1; i<N; ++i)mm[i]=(i&(i-1))?mm[i-1]:mm[i-1]+1;
    while(~scanf("%d%d",&n,&q)) {
        for(int i=1; i<=1000000; ++i)mat[i] = 0;
        for(int i=1; i<=n; ++i) {
            mn[i][0]=read();
            mx[i][0]=mn[i][0];
            pre[i][0]=mat[mn[i][0]];
            mat[mn[i][0]]=i;
            if(i>1)gcd[i-1][0] = abs(mn[i][0]-mn[i-1][0]);
        }
        init();
        while(q--) {
            int l=read(),r=read();
            if(l==r) {
                printf("Yes\n");
                continue;
            }
            int x=getmn(l,r),y=getmx(l,r);
            if(x==y) {
                printf("Yes\n");
                continue;
            }
            if(getpre(l,r)>=l) {
                printf("No\n");
                continue;
            }
            int d = getgcd(l,r-1);
            if(x+1ll*(r-l)*d==y)printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}

 

以上是关于dutacm.club 1094: 等差区间(RMQ区间最大最小值,区间GCD)的主要内容,如果未能解决你的问题,请参考以下文章

1094 和为k的连续区间

51nod 1094 和为k的连续区间前缀和/区间差/map

51Nod - 1094 和为k的连续区间

51nod 1094STL和为k的连续区间

51Nod 1094 和为k的连续区间 | 水

51nod 1094 和为k的连续区间