浙江师范大学第十八届大学生程序设计竞赛(重现) H - 车辆探测器
题意
(n)辆汽车在(x)轴负半轴排成一列以每秒(1)米的速度匀速向(x)正半轴行驶,第(i)辆汽车的初始位置为(a[i])。
有(m)个车辆探测器,探测范围为(pm r[i])的探测器被放在(x)正半轴((r[i],0))的位置。
只要每个车辆探测器的探测范围内有车存在,那么每秒会消耗(P)焦耳的能量。
如果原本探测范围内没有车存在,车辆探测器会关闭,一旦有车进入探测范围,探测器每次打开需要消耗(C)焦耳的能量。
对于每个探测器,分别求出它们消耗的能量。
限制
(1leq nleq 10^5)
(1leq mleq 10^5)
(1leq P,Cleq 10^6)
(-2 imes 10^6le a[i]lt a[i+1]lt 0)
(1le r[i]le 10^8)
思路
一下子一年就过去了呢,这题去年正式比赛时没有过多少人,借这次重现赛重新写一遍整理思路
当时应该是树状数组过的,现在想了下好像差分数组直接就可以做,还更方便
(一年过去了思维还是没有什么质的飞跃呢……)
换句话说,对于每个探测范围为(pm r)的探测器,其探测的左右最大距离即为(2r)
所以只要有两辆车的间隔(gt 2r),那么探测器就会多消耗(C)焦耳的能量
先假设探测器从第(1)辆车进入探测范围开始,到第(n)辆车离开探测范围结束,它都在进行工作,那么总共消耗的能量为(P imes(a[n]-a[1]+2r))
然后我们需要求出所有(gt 2r)的间隔减去(2r)后的总和,这就是探测器不进行工作的时间长度
对于所有的(n-1)个间隔,先设(gt 2r)的间隔数量为(upperCount)
如果我们能够找出所有(gt 2r)的间隔的长度总和(uselessLen),就可以通过(uselessLen-2r imes upperCount)来得到上述的探测器不进行工作的时间长度
对于(gt 2r)的间隔数量与(gt 2r)的间隔长度总和,由于只存在询问不存在修改,故可以直接通过建立两个前缀和数组
如果某两辆车的间隔为(d),可以在维护数量的数组里(d)位置(+1),在维护长度的数组里(d)位置(+d)
在取值时,(arrayCount[2r])可以表示长度(le 2r)的间隔数量,故(upperCount=(n-1)-arrayCount[2r])
(arrayLen[2r])可以表示长度(le 2r)的间隔长度总和,故(uselessLen=(a[n]-a[1]+ar)-arrayLen[2r]-2r imes upperCount)
程序
(注意有些读入挂可能会WA Case 1)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[100050];
ll ar1[2000050],ar2[2000050];
int main()
{
int n,m,P,C;
scanf("%d%d%d%d",&n,&m,&P,&C);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(i!=1)
{
int d=a[i+1]-a[i];
ar1[d]++;
ar2[d]+=d;
}
}
for(int i=1;i<=2000000;i++)
{
ar1[i]+=ar1[i-1];
ar2[i]+=ar2[i-1];
}
int TotalLen=a[n]-a[1];
for(int i=1;i<=m;i++)
{
int r;
scanf("%d",&r);
if(r>=1000000) //这种探测器不会关闭,不需要讨论
{
printf("%lld
",1LL*P*(TotalLen+2*r)+C);
continue;
}
int upperCount=(n-1)-ar1[2*r]; //求出>2r的间隔数量
int uselessLen=TotalLen-ar2[2*r]; //求出>2r的间隔长度-2r后的和
int Len=(TotalLen+2*r)-(uselessLen-2*r*upperCount); //可行长度
printf("%lld
",1LL*P*Len+1LL*C*(upperCount+1)); //一开始就需要进行一次开启
}
return 0;
}