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(1≤l≤r≤n),表示询问区间 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;
}
时间: 2024-10-22 11:23:52

dutacm.club 1094: 等差区间(RMQ区间最大、最小值,区间GCD)的相关文章

F题:等差区间(RMQ)

原题大意:原题链接  题解链接 给定一个长为n的数组元素和q次区间[l,r]询问,判断区间[l,r]内元素排序后能否构成等差数列 #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=1e5+10; int n,q,l,r; int a[maxn],temp[1000010]; int mi[maxn

CodeForces 52C Circular RMQ(区间循环线段树,区间更新,区间求和)

转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://codeforces.com/problemset/problem/52/C You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segm

CF#52 C Circular RMQ (线段树区间更新)

Description You are given circular array a0,?a1,?...,?an?-?1. There are two types of operations with it: inc(lf,?rg,?v) - this operation increases each element on the segment [lf,?rg] (inclusively) by v; rmq(lf,?rg) - this operation returns minimal v

RMQ(模板 ST 区间最值,频繁的间隔时间)

PS: 介绍:http://blog.csdn.net/liang5630/article/details/7917702 RMQ算法.是一个高速求区间最值的离线算法,预处理时间复杂度O(n*log(n)).查询O(1).所以是一个非常高速的算法,当然这个问题用线段树相同可以解决. 1.求区间的最大值和最小值! 代码例如以下: #include <cstdio> #include <cstring> #include <cmath> #include <iostr

hdu 5919 主席树(区间不同数的个数 + 区间第k大)

Sequence II Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 849    Accepted Submission(s): 204 Problem Description Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,?

给出一个区间[a, b],计算区间内“神奇数”的个数。 神奇数的定义:存在不同位置的两个数位,组成一个两位数(且不含前导0),且这个两位数为质数。 比如:153,可以使用数字3和数字1组成13,13是质数,满足神奇数。同样153可以找到31和53也为质数,只要找到一个质数即满足神奇数。

给出一个区间[a, b],计算区间内"神奇数"的个数.神奇数的定义:存在不同位置的两个数位,组成一个两位数(且不含前导0),且这个两位数为质数.比如:153,可以使用数字3和数字1组成13,13是质数,满足神奇数.同样153可以找到31和53也为质数,只要找到一个质数即满足神奇数. 输入描述: 输入为两个整数a和b,代表[a, b]区间 (1 ≤ a ≤ b ≤ 10000). 输出描述: 输出为一个整数,表示区间内满足条件的整数个数 输入例子: 11 20 输出例子: 6 1 #in

hdu-3333 Turing Tree 离线区间+树状数组(区间不同数的和)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3333 题目大意: 给出一数组,以及m个查询区间,每次查询该区间不同数字的和.相同数字只加一次. 解题思路: 离线区间,按照区间右端点进行排序. 这样可以从左到右扫一遍,用尺取法一个一个将数字放入树状数组中. 如果这个数字已经在树状数组里面,记录之前的下标,再从树状数组中删去之前下标的这个数字,在当前下标添加该数字.这样可以保证每一步操作,都会使得树状数组中没有重复元素.这样可以直接用树状数组求不同

POJ - 2528 区间离散化,线段树区间修改,区间询问

这个题非常有意思的地方是,我们发现区间[1,4]和[5,8]是紧挨着的,因为这个的数代表的是一段区间,原本我们对于普通的离散, a[1]=1,a[2]=5,a[3]=6,a[4]=8;数组下标就是重新离散的位置,但是a[2]和a[3]明显不重叠,为此我们需要重新考虑离散的内容,其实不妨这样,如果区间的间隔大于1,那么我们插入一个数a[i]+1,这样就强行把a[i]和a[i+1]分开,因为 如三张海报为:1~10 1~4 6~10 离散化时 X[ 1 ] = 1, X[ 2 ] = 4, X[ 3

POJ 3468 区间更新(求任意区间和)A Simple Problem with Integers

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 163977   Accepted: 50540 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type o