1094: 等差区间
Time Limit:5000/3000 MS (Java/Others) Memory Limit:163840/131072 KB (Java/Others)
Total Submissions:655 Accepted:54
[Submit][Status][Discuss]Total Submissions:655 Accepted:54
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
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 "); continue; } int x=getmn(l,r),y=getmx(l,r); if(x==y) { printf("Yes "); continue; } if(getpre(l,r)>=l) { printf("No "); continue; } int d = getgcd(l,r-1); if(x+1ll*(r-l)*d==y)printf("Yes "); else printf("No "); } } return 0; }