HDU-5101,二分算法

題意

對於一組有m個數,如果要取兩個數a和b,使得這兩個數的和大於k,那麼可以將這組數由小到大排序,然後枚舉a,查找滿足條件的數b的個數,在查找數b的個數時,可以利用lower_bound函數(二分查找)。比如:我們找到第一個滿足a+b>k的b是第i個數,則第i+1,i+2,……一直到最後一個數都滿足。枚舉a的過程記數並加和,得到的結果就是滿足條件的(a,b)對的2倍。(因爲你每個人都要加一遍,所有人實際上都重複加了一次,給小學數學中,握手問題差不多,每個人都去給所有人握手,然後,每個人都會給同一個人握兩次手),所以答案要除以2;

題目要求不同的集合,可以利用總集合中滿足條件的數對 - 相同集合滿足條件的集合數對。

(注意:單個集合的數最多有100,集合數目最多有1000,則總集合的數最多有100000)

下面代碼詳細解釋

#include<stdio.h>
#include<string.h>
#include<algorithm> 
#include<math.h>
using namespace std;
typedef long long ll;
struct IQ {
	ll m;
	ll v[100005];
}a[1005];
int main()
{
	ll i,j,l,m,n,v,k,t;
	scanf("%I64d",&t);
	while(t--){
		scanf("%I64d%I64d",&n,&k);
		a[0].m=0;//標記總人數
		for( i=1,l=0;i<=n;i++)
		{
			scanf("%I64d",&m);
			a[i].m=m;//第幾個班有多少人
			a[0].m+=m;//共有多少人存放在a[0].m中
			for(j=0;j<m;j++){
				scanf("%I64d",&v);
				a[i].v[j]=v;//i班每個同學的成績,存放在數組裏 
				a[0].v[l++]=v; //將每個同學的成績都存在a[0].v[]數組內 
			}
			sort(a[i].v,a[i].v+m);//將本班同學的成績排序 
		} 
		sort(a[0].v,a[0].v+a[0].m);	//將所有同學成績排序
		ll ans=0;
		for(i=1;i<=n;i++)
		{
			for(j=0;j<a[i].m;j++)
			{
				v=a[i].v[j];
				ll x=lower_bound(a[0].v,a[0].v+a[0].m,k-v+1)-a[0].v;//(k-v+1)Dudu智商是k,然後這個人的智商是v,找到比k大的數.a[0].v是數組的起始位置
				ll n1=a[0].m-x;
				ll y=lower_bound(a[i].v,a[i].v+a[i].m,k-v+1)-a[i].v;//同上
				ll n2=a[i].m-y;
				ans+=n1-n2;
			}
		} 
		printf("%I64d\n",ans/2);
	}
	return 0;
} 

 

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