宛如自己是一个智障。。。打错1个字母,调了一天。。。。
二分找出第10000次超越发生的时间,然后N*N时间内计算答案。由于许多都会被continue,所以进行直线交的计算次数只有1W,不会超时。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=10010;
int n;
struct preson
{
int index,ordinal,m,s,now;
}pres[MAXN];
bool cmp1(preson p1,preson p2)
{
return p1.m<p2.m;
}
bool cmp2(preson p1,preson p2)
{
return p1.now<p2.now;
}
int cal(int tim)
{
int i,ret=0;
for(i=0;i<n;i++)
pres[i].now=pres[i].m+pres[i].s*tim;
sort(pres,pres+n,cmp2);
for(i=0;i<n;i++)
ret+=max(0,i-pres[i].index);
return ret;
}
pair<double,double> intersection(long long x1,long long y1,long long x2,long long y2,long long x3,long long y3,long long x4,long long y4)
{
long long a0,b0,c0,a1,b1,c1,div;
double x,y;
a0=y1-y2; b0=x2-x1; c0=x1*y2-x2*y1;
a1=y3-y4; b1=x4-x3; c1=x3*y4-x4*y3;
div=a0*b1-a1*b0;
x=(b0*c1-b1*c0)*1.0/div;
y=(a1*c0-a0*c1)*1.0/div;
return make_pair(x,y);
}
struct result
{
int down,up;
double tim;
}ans[MAXN<<2];
bool cmp3(result r1,result r2)
{
if(r1.tim!=r2.tim)
return r1.tim<r2.tim;
if(r1.up!=r2.up)
return r1.up<r2.up;
return r1.down<r2.down;
}
int main()
{
int i,j,lef,rig,mid,limit,cnt;
pair<double,double> tmp;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<n;i++)
{
scanf("%d%d",&pres[i].m,&pres[i].s);
pres[i].ordinal=i+1;
}
sort(pres,pres+n,cmp1);
for(i=0;i<n;i++)
pres[i].index=i;
lef=0;rig=MAXN*10;
while(lef<=rig)
{
mid=(lef+rig)>>1;
if(cal(mid)>=11000)
rig=mid-1;
else
lef=mid+1;
}
cal(lef);
cnt=0;
for(i=0;i<n;i++)
{
for(j=0;j<i;j++)
{
if(pres[j].m>pres[i].m)
{
tmp=intersection(pres[j].m,0,pres[j].now,lef,pres[i].m,0,pres[i].now,lef);
ans[cnt].up=pres[i].ordinal;
ans[cnt].down=pres[j].ordinal;
ans[cnt++].tim=tmp.second;
}
}
}
sort(ans,ans+cnt,cmp3);
if(!cnt)
printf("No Solution\n");
else
{
limit=min(10000,cnt);
for(i=0;i<limit;i++)
{
printf("%d %d\n",ans[i].up,ans[i].down);
}
}
}
}