浙江师范大学第十八届大学生程序设计竞赛(重现) H - 车辆探测器
题意
\(n\)辆汽车在\(x\)轴负半轴排成一列以每秒\(1\)米的速度匀速向\(x\)正半轴行驶,第\(i\)辆汽车的初始位置为\(a[i]\)。
有\(m\)个车辆探测器,探测范围为\(\pm r[i]\)的探测器被放在\(x\)正半轴\((r[i],0)\)的位置。
只要每个车辆探测器的探测范围内有车存在,那么每秒会消耗\(P\)焦耳的能量。
如果原本探测范围内没有车存在,车辆探测器会关闭,一旦有车进入探测范围,探测器每次打开需要消耗\(C\)焦耳的能量。
对于每个探测器,分别求出它们消耗的能量。
限制
\(1\leq n\leq 10^5\)
\(1\leq m\leq 10^5\)
\(1\leq P,C\leq 10^6\)
\(-2\times 10^6\le a[i]\lt a[i+1]\lt 0\)
\(1\le r[i]\le 10^8\)
思路
一下子一年就过去了呢,这题去年正式比赛时没有过多少人,借这次重现赛重新写一遍整理思路
当时应该是树状数组过的,现在想了下好像差分数组直接就可以做,还更方便
(一年过去了思维还是没有什么质的飞跃呢……)
换句话说,对于每个探测范围为\(\pm r\)的探测器,其探测的左右最大距离即为\(2r\)
所以只要有两辆车的间隔\(\gt 2r\),那么探测器就会多消耗\(C\)焦耳的能量
先假设探测器从第\(1\)辆车进入探测范围开始,到第\(n\)辆车离开探测范围结束,它都在进行工作,那么总共消耗的能量为\(P\times(a[n]-a[1]+2r)\)
然后我们需要求出所有\(\gt 2r\)的间隔减去\(2r\)后的总和,这就是探测器不进行工作的时间长度
对于所有的\(n-1\)个间隔,先设\(\gt 2r\)的间隔数量为\(upperCount\)
如果我们能够找出所有\(\gt 2r\)的间隔的长度总和\(uselessLen\),就可以通过\(uselessLen-2r\times 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\times 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\n",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\n",1LL*P*Len+1LL*C*(upperCount+1)); //一开始就需要进行一次开启
}
return 0;
}