题意:
一条一维数轴上,有n个左端点为xi,长度l的区间。以向右为正方向,第i个区间的移动速度为vi+w(vi=1或-1,|w|<=wmax,所有区间的w相同)。
输入n,l,wmax,vi。
输出无序数对(i,j)的个数,使第i个区间和第j个区间有一个合法的w的取值,在某一时刻同时覆盖原点(不包括区间左、右边界)。
(n<=1e5)
思路:
因为w的取值是不定的,所以可以看成是每个区间以vi的速度运动,而原点以-w的速度运动。
很容易画出一个时间-位置图像(横轴位置,纵轴时间),其中橙色区域为原点在对应时间可能的位置。
可以发现,只要第i个和第j个区间所相交形成的斜正方形与橙色区域有公共部分,则说明(i,j)是我们要求的一个无序数对。
很显然只要考虑斜正方形最上面的顶点即可。
那么可以将v=1和v=-1的区间分开,给v=-1的区间排序。
然后对每一个v=1的区间二分查找一个x最小的v=-1的区间,使其相交的斜正方形区域与橙色区域有交集,统计答案即可。
完了。
记得开long long。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cmath> 6 #include <algorithm> 7 using namespace std; 8 typedef long long LL; 9 int read(){ 10 int x=0,f=1;char ch=getchar(); 11 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 12 while(ch>=‘0‘&&ch<=‘9‘){x=(x<<3)+(x<<1)+ch-‘0‘;ch=getchar();} 13 return x*f; 14 } 15 const int SIZE=100005; 16 int n,l,w,ans,ch; 17 int lf[SIZE],rt[SIZE],lnt,rnt; 18 bool check(int mid){ 19 mid=lf[mid]+l; 20 double h=(double)(mid-ch)/2;//斜正方形最上面的顶点的纵坐标。 21 if(h>fabs((double)(mid+ch)/(2.0*w))) return 1; 22 else return 0; 23 } 24 void bisearch(int l,int r){ 25 if(l>r) return; 26 int mid=((l+r)>>1); 27 if(check(mid)){ 28 ans=mid; 29 bisearch(mid+1,r); 30 } 31 else bisearch(l,mid-1); 32 } 33 bool cmp(int x,int y){ 34 return x>y; 35 } 36 int main(){ 37 n=read(),l=read(),w=read(); 38 for(int i=1;i<=n;i++){ 39 int x=read(),v=read(); 40 if(v==1) rt[++rnt]=x; 41 else lf[++lnt]=x; 42 } 43 sort(lf+1,lf+lnt+1,cmp); 44 LL rez=0; 45 for(int i=1;i<=rnt;i++){ 46 ans=0; 47 ch=rt[i];//ch存当前正在查询的v=1的区间的左边界。 48 bisearch(1,lnt); 49 rez+=ans; 50 } 51 printf("%I64d\n",rez); 52 return 0; 53 }
原文地址:https://www.cnblogs.com/KuriyamaMirai/p/9196796.html
时间: 2024-10-10 01:07:20