标签:
题意:给出n个元素的数组a和m个元素的数组b,求数组a中元素与数组b中元素相乘所得乘积的第k大值;
思路:暴力超时,采用二分;先将两数组从大到小排序,外层二分枚举答案,内层二分查找与当前枚举值相等的乘积所在的区间;
#include<cstdio> #include<cstring> #include<algorithm> typedef long long ll; #define inf 100000000010 using namespace std; ll kth,n,m; ll a[500010],b[500010]; int cmp(int a1,int b1) { return a1>b1; } int main() { int k,i,j; while(scanf("%lld%lld%lld",&n,&m,&kth)!=EOF) { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(i=1;i<=n;i++) scanf("%lld",&a[i]); for(i=1;i<=m;i++) scanf("%lld",&b[i]); sort(a+1,a+n+1,cmp); sort(b+1,b+m+1,cmp); b[0]=inf;b[m+1]=-1; ll Min=a[n]*b[m]; ll Max=a[1]*b[1]; ll Low=Min; ll High=Max; ll ans=Max; while(Low<=High) { ll Mid=(Low+High)/2; ll key=Mid; ll s1=0,s2=0; for(i=1;i<=n;i++) { int low,high,res; ll val=a[i]*b[1]; ll val2=a[i]*b[m]; if(val2>key) { s1+=m; continue; } if(val<key) { s2+=m; continue; } low=1,high=m,res=0; while(low<=high) { int mid=(low+high)/2; val=a[i]*b[mid]; val2=a[i]*b[mid+1]; if(val>key&&val2<=key) { res=mid; break; } else if(val2>key) low=mid+1; else high=mid-1; } s1+=res; low=1,high=m,res=m+1; while(low<=high) { int mid=(low+high)/2; val=a[i]*b[mid]; val2=a[i]*b[mid-1]; if(val<key&&val2>=key) { res=mid;break; } else if(val2<key) { high=mid-1; } else low=mid+1; } s2+=(m-res+1); } ll left=s1+1; ll right=n*m-s2; if(left<=kth&&kth<=right) { ans=key;break; } else if(kth<left) { Low=Mid+1; } else High=Mid-1; } printf("%lld\n",ans); } return 0; }
标签:
原文地址:http://www.cnblogs.com/dashuzhilin/p/4574906.html