N - 信心题
给定一个含有n个数字的数列,每个数字都有一个值a[i](下标从1开始)。定义第i个数字和第j个数字间的距离dis(i,j)=abs(i-j)。
接下来给出q个询问,每次询问一个区间[l,r],要求求出一对数字(i,j)(l<=i<=j<=r),使得a[i]=a[j]并且dis(i,j)最大,由于这样的数对可能有多个,因此答案只要输出dis。
Input
题目包含多组数据
每组数据第一行一个数n
第二行n个数字,表示数列a
第三行一个数字q,表示询问个数
接下来q行,每行两个数l,r,表示询问
N<=10^5
Q<=10^4
1<=a[i]<=10^3
1<=l<=r<=n
Output
每个询问输出一个数组dis
Sample Input
5 1 2 3 1 2 3 3 3 2 5 1 5
Sample Output
0 3 3
虽说是信心题,但还是比较麻烦的,这个用的算法是莫队算法,大体思路就是建立一个position[数字值][从左到右第几个] = 该值在给出数列的位置。
下面是代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <stack>
#include <queue>
using namespace std;
#define ll long long
const int maxn = 1e5+5;
struct node
{
int l,r,id;
}que[maxn];
vector<int> position[1005];//存放每个值的位置
int cur[maxn];
int l[maxn],r[maxn];
int ans[maxn];
int n,q,limit;
bool cmp(node a,node b)
{
if(a.l/limit == b.l/limit)
return a.r < b.r;
return a.l < b.l;
}
int main()
{
while(scanf("%d",&n) != EOF)
{
memset(l,-1,sizeof(l));
memset(r,-1,sizeof(r));
for(int i = 1;i <= 1000;i++)
position[i].clear();
for(int i = 1;i <= n;i++)
{
scanf("%d",&cur[i]);
position[cur[i]].push_back(i);
}
scanf("%d",&q);
for(int i = 1;i <= q;i++)
{
scanf("%d%d",&que[i].l,&que[i].r);
que[i].id = i;
}
limit = (int)(sqrt(n)+0.5);
sort(que+1,que+1+q,cmp);
int L,R;
L = R = 0;
for(int i = 1;i <= q;i++)
{
while(L < que[i].l)
{
l[cur[L]]++;
L++;
}
while(R > que[i].r)
{
r[cur[R]]--;
R--;
}
while(L > que[i].l)
{
L--;
l[cur[L]]--;
}
while(R < que[i].r)
{
R++;
r[cur[R]]++;
}
int maxx = 0;
for(int j = 1;j <= 1000;j++)
{
if(r[j] <= 0)
continue;
int l1 = position[j][l[j]+1];
//上面为什么加1?举个例子很容易懂:
//对于数列1 2 2 1,如果是区间[1,4],那么l[1] = -1,r[1] = 1
int rr = position[j][r[j]];
maxx = max(maxx,rr-l1);
}
ans[que[i].id] = maxx;
}
for(int i = 1;i <= q;i++)
printf("%d\n", ans[i]);
}
//cout << "AC" <<endl;
return 0;
}