题意:中文题,他给的半径实际上就是两点之间的距离,然后要求找出两个点的权值加上之间的距离最大。
a数组表示每个点的权值,设两个点分别是i,j,所以答案就是a[i]-i*r+a[j]+j*r,对于一个j应该要找到满足要求最大的a[i]-i*r,所以就用单调队列了,还要注意就是单调队列里相等的话就直接加到队尾,优先取编号小的。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=100010;
typedef long long ll;
typedef pair<ll,ll> Point;
int q[MAXN<<1];
ll a[MAXN<<1];
int main()
{
int t,n,i,flag=1;
ll r;
scanf("%d",&t);
while(t--)
{
scanf("%d%lld",&n,&r);
for(i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
a[i+n]=a[i];
}
int front=0,rear=-1;
Point ans;
ll aans=0;
q[++rear]=1;
for(i=2;i<=2*n;i++)
{
while(front<=rear&&(i-q[front])>n/2)
front++;
if(front<=rear&&a[i]+a[q[front]]-q[front]*r+i*r>aans)
{
aans=a[i]+a[q[front]]-q[front]*r+i*r;
ans.first=min(q[front],i);
ans.second=max(q[front],i);
if(ans.first>n)
ans.first-=n;
if(ans.second>n)
ans.second-=n;
if(ans.first>ans.second)
swap(ans.first,ans.second);
}
else if(front<=rear&&a[i]+a[q[front]]-q[front]*r+i*r==aans)
{
Point temp;
temp.first=min(q[front],i);
temp.second=max(q[front],i);
if(temp.first>n)
temp.first-=n;
if(temp.second>n)
temp.second-=n;
if(temp.first>temp.second)
swap(temp.first,temp.second);
if(temp<ans)
{
ans=temp;
}
}
while(front<=rear&&a[q[rear]]-q[rear]*r<a[i]-i*r) //相等的情况先取前面的
rear--;
q[++rear]=i;
}
printf("Case #%d:\n%lld %lld\n",flag++,ans.first,ans.second);
}
return 0;
}
博客介绍了如何使用单调队列解决ACM竞赛题目HDU5261(蜀道难)。题目要求根据点的权值和两点间距离,寻找权值加上距离的最大值。通过维护一个单调队列,可以找到满足条件的最大权值,同时处理相等权值时选择编号较小的点。
658

被折叠的 条评论
为什么被折叠?



