51nod 1112 KGold

宛如自己是一个智障。。。打错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);
			}
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值