pku3685 二分

http://poj.org/problem?id=3685

題意:一個50000*50000的矩陣,每個元素值爲: i2 + 100000 × i + j2 - 100000 × j + i × j,
求這個矩陣中的第k小值。。。




分析:做法用了類似前面一篇二分的方法,先二分枚舉結果val,很明顯每一列是遞增的,那麼掃描每一列再二分求比val小的值的個數。。。。但是兩個二分實在太慢了。2000+MS。。。仰慕0ms的程序。。。

發現一元二次方程的特徵都忘了。。。第一次居然冒失的去枚舉行去了,單調性都沒分析。。。。

用解方程的方法要用double,老是結果不對,不知道爲什麼。。。。
------------搞了半天,原來還不是double的問題,還是二分出了點小錯。。。汗啊啊啊啊啊啊。。。


代碼:
300+ms

#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;

const __int64 inf=10000000000;
__int64 n, k;

//通過解方程,求值<num的個數。。。。
__int64 bs2(__int64 i, __int64 num)
{
	__int64 xx1, xx2;
	double x1, x2, delt, b, c;
	b = i-100000;
	c = i*i+100000*i-num;
	delt = b*b-4*c;
	if(delt<=0)
		return 0;
	delt = sqrt(delt);
	x1 = (-b+delt)/(2);
	x2 = (-b-delt)/(2);
	if(x1>x2)
		swap(x1, x2);
	xx1 = x1;
	xx1++;
	xx2 = x2;
	if(xx2==x2)
		xx2--;
	if(xx1>n)
		return 0;
	if(xx2<1)
		return 0;
	if(xx1<1)
		xx1 = 1;
	if(xx2>n)
		xx2 = n;
	return xx2-xx1+1;
}

__int64 bs() 
{
	__int64 l, r, mid, cnt, i;
	l=-inf, r=inf;
	while(l<=r)
	{
		mid = (l+r)/2;
		cnt = 0;
		for(i=1; i<=n; i++)
			cnt += bs2(i, mid);
		if(cnt>=k)
			r = mid-1;
		else
			l = mid+1;
	}
	return l-1;
}

int main()
{
	int cas;
	scanf("%d", &cas);
	while(cas--)
	{
		scanf("%I64d%I64d", &n, &k);
		printf("%I64d\n", bs());
	}
	return 0;
}



代碼:
2000+MS
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;

const __int64 inf=10000000000;
__int64 n, k;

__int64 bs1(__int64 i, __int64 num) //枚舉列,每一列一定單調增的。。。
{
	__int64 l, r, mid, tmp;
	l=1, r=n;
	while(l<=r)
	{
		mid = (l+r)/2;
		//tmp = i*i+100000*i+mid*mid-100000*mid+i*mid;
		tmp = mid*mid+100000*mid+i*i-100000*i+i*mid;
		if(tmp<num)
			l = mid+1;
		else
			r = mid-1;
	}
	return r;
}

__int64 bs() 
{
	__int64 l, r, mid, cnt, i;
	l=-inf, r=inf;
	while(l<=r)
	{
		mid = (l+r)/2;
		cnt = 0;
		for(i=1; i<=n; i++)
			cnt += bs1(i, mid);
		if(cnt>=k)
			r = mid-1;
		else
			l = mid+1;
	}
	return l-1;
}

int main()
{
	int cas;
	scanf("%d", &cas);
	while(cas--)
	{
		scanf("%I64d%I64d", &n, &k);
		printf("%I64d\n", bs());
	}
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章