V.[NOI2004]降雨量
本题思路就和I.[HNOI2012]三角形覆盖问题差不多了。
首先,我们特判掉有长度为\(W\)的伞的情况——此时答案即为\(0\)。
否则,对于每一时刻,我们计算出下面三种情况中,最先来到的一个:
-
有一把伞撞到了边缘
-
有两把伞,它们的某两个边缘相遇了(不管是哪两个边缘)
-
时刻\(T\)
然后就可以仍然使用梯形面积公式解决了(相遇的伞在空间中扫过的距离可以被看做梯形)。
因为题目保证所有伞的总往返次数不会超过\(250\),又此时每对不同的伞的每对往返都最多可以贡献一次相遇,故总相遇次数不会超过\(250^2\times 4=250000\)次(其中\(4\)是因为相遇时最多会有\(4\)个边缘相遇)。显然可以通过。
代码:
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-9;
int n,m,T,ita,ord[11];
double L[11],R[11],res;
int v[11];
double nex(){
double minn=0x3f3f3f3f,tmp;
for(int i=1;i<=n;i++){
if(v[i]>0)minn=min(minn,(m-R[i])/v[i]);
if(v[i]<0)minn=min(minn,L[i]/(-v[i]));
}
// printf("%lf\n",minn);
for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++){
if(v[j]==v[i])continue;
tmp=(R[j]-L[i])/(v[i]-v[j]);if(tmp>eps)minn=min(minn,tmp);
tmp=(L[j]-L[i])/(v[i]-v[j]);if(tmp>eps)minn=min(minn,tmp);
tmp=(L[j]-R[i])/(v[i]-v[j]);if(tmp>eps)minn=min(minn,tmp);
tmp=(R[j]-R[i])/(v[i]-v[j]);if(tmp>eps)minn=min(minn,tmp);
}
// printf("%lf\n",minn);
return minn;
}
void upd(double delta){
for(int i=1;i<=n;i++)if(v[i])L[i]+=delta*v[i],R[i]+=delta*v[i];
for(int i=1;i<=n;i++){
if(!v[i])continue;
if(fabs(L[i])<eps)v[i]=abs(v[i]);
if(fabs(m-R[i])<eps)v[i]=-abs(v[i]);
}
}
int qwq[11],tp;
double calc(){
sort(ord+1,ord+n+1,[](int u,int v){return R[u]<R[v];});
tp=0;
for(int i=1;i<=n;i++){
while(tp&&L[qwq[tp]]>L[ord[i]])tp--;
qwq[++tp]=ord[i];
}
double ret=0;
// for(int i=1;i<=tp;i++)printf("[%lf %lf]\n",L[qwq[i]],R[qwq[i]]);
for(int i=1;i<=tp;i++)ret+=R[qwq[i]]-max(L[qwq[i]],R[qwq[i-1]]);
return ret;
}
int main(){
scanf("%d%d%d%d",&n,&m,&T,&ita);
for(int i=1;i<=n;i++){
scanf("%lf%lf%d",&L[i],&R[i],&v[i]);
if(R[i]==m){puts("0.00");return 0;}
R[i]+=L[i],ord[i]=i;
}
upd(0);
double tim=0,las=calc();
while(fabs(T-tim)>eps){
double delta=nex();
delta=min(delta,T-tim);
upd(delta);
// for(int i=1;i<=n;i++)printf("[%lf %lf]\n",L[i],R[i]);
double now=calc();
// printf("(%lf %lf):%lf\n",now,las,delta);
res+=(now+las)*delta/2;
las=now;
tim+=delta;
}
printf("%.2lf\n",(m*T-res)*ita);
return 0;
}