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
题目大意:给定一个数列,并给出很多区间询问,问是否是等差数列。题解:这道题目用了一个很好的判断等差数列的思想,首先如果区间内最大值与最小值相同,那么一定是等差数列不然的话,判断区间和与(max+min)*n/2是否相等,如不相等那么输出No,否则再判断区间gcd,如果是等差数列那么它的区间gcd应该等于其公差(这里是我觉得最精华的地方),而公差我们可以用(max-min)/(n-1)来计算得到
其中区间最值用线段树维护,区间gcd也用线段树维护
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; #define int long long const int MAX = 1e5+6; const int INF = 1e9; int n,q; int A[MAX]; int stmax[MAX<<2]; int stgcd[MAX<<2]; int stmin[MAX<<2]; int sum[MAX]; int gcd(int a,int b) { if(b == 0) return a; return gcd(b,a % b); } void init(int v,int l,int r) { if(r - l == 1) { stmax[v] = stmin[v] = A[l]; stgcd[v] = abs(A[l+1]-A[l]); } else { init(2*v+1,l,(l+r)/2); init(2*v+2,(l+r)/2,r); stmax[v] = max(stmax[2*v+1],stmax[2*v+2]); stmin[v] = min(stmin[2*v+1],stmin[2*v+2]); stgcd[v] = gcd(stgcd[2*v+1],stgcd[2*v+2]); } } int querymin(int v,int a,int b,int l,int r) { if(l <= a && r >= b) return stmin[v]; else if(b <= l || r <= a) return INF; else return min(querymin(2*v+1,a,(a+b)/2,l,r),querymin(2*v+2,(a+b)/2,b,l,r)); } int querymax(int v,int a,int b,int l,int r) { if(l <= a && r >= b) return stmax[v]; else if(b <= l || r <= a) return 0; else return max(querymax(2*v+1,a,(a+b)/2,l,r),querymax(2*v+2,(a+b)/2,b,l,r)); } int querygcd(int v,int a,int b,int l,int r) { if(l <= a && r >= b) return stgcd[v]; else if(b <= l || r <= a) return 0; else return gcd(querygcd(2*v+1,a,(a+b)/2,l,r),querygcd(2*v+2,(a+b)/2,b,l,r)); } main() { while(~scanf("%lld%lld",&n,&q)) { sum[0] = 0; for(int i = 0;i < n;i++) { scanf(" %lld",&A[i]); sum[i+1] = sum[i] + A[i]; } A[n] = A[n-1]; init(0,0,n); for(int i = 0;i < q;++i) { int l,r; scanf("%lld%lld",&l,&r); if(r - l <= 1) { puts("Yes"); continue; } int mini = querymin(0,0,n,l-1,r); int maxi = querymax(0,0,n,l-1,r); if(maxi == mini) { puts("Yes"); continue; } //cout<<r<<" "<<l-1<<endl; if((sum[r] - sum[l-1])*2 != (maxi + mini) * (r-l+1)) { puts("No"); continue; } int d = (maxi - mini) / (r - l); if((maxi-mini)%(r-l) == 0 && querygcd(0,0,n,l-1,r-1) == d) puts("Yes"); else puts("No"); } } return 0; }