在卿学姐B站上的视频看到这道题,顺便学习了一下卿式二分。https://www.bilibili.com/video/av7540836/#page=2
1 int l=L, r=R; 2 while(l<=r){ 3 int mid=(l+r)/2; 4 if (check(mid)) { 5 ans=mid; 6 r=mid-1; 7 }else l=mid+1; 8 } 9 return ans;
题意:两个集合,X={x | x=2a, a为正整数},Y={y | y=3b, b为正整数},其中XY的中元素的个数分别为n、m。两个集合没有交集,求两个集合可能的最小的最大值。
两种思路:
1. 二分查找
三个约束条件,① i/2>=n; ② i/3>=m; ③ i/2+i/3-i/6>=n+m; (去掉重复的)
前两个约束条件是为了满足两个集合个数,第三个约束条件描述了“两个集合没有交集”,第三个约束条件不是很好写。
这道题应该是不用二分也能过,但是还是用二分写一个。check单独写了一个函数,算是练练卿式二分的模板。
1 #include <cstdio> 2 using namespace std; 3 4 int check(int i,int a,int b){ 5 if (i/2>=a && i/3>=b && i/2+i/3-i/6>=a+b ) return 1; 6 else return 0; 7 } 8 9 int main(){ 10 11 int l=2,r=6000010,mid,ans,n,m; 12 scanf("%d%d",&n,&m); 13 while (l<=r){ 14 mid=(l+r)/2; 15 if (check(mid,n,m)) { 16 ans=mid;r=mid-1; 17 }else l=mid+1; 18 } 19 printf("%d\n",ans); 20 return 0; 21 }
2. 贪心
问题转化为求一个只由2a,3b构成的数列中第n+m大的数(a,b=0,1,2…),令n=2n,m=3m后每次比较n和m的大小,n小就给n加2,m小就给m加3,操作min(n,m)/6次(2,4,6,…,2n和3,6,9,…3m重复了这么多次)之后输出n和m的最大值即可。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 int n,m; 6 int main() 7 { 8 while(~scanf("%d%d",&n,&m)) 9 { 10 n*=2,m*=3; 11 for(int i=1;i<=min(n,m)/6;i++) 12 if(n>m)m+=3; 13 else n+=2; 14 printf("%d\n",max(n,m)); 15 } 16 return 0; 17 }