• [CSP-S模拟测试]:分组配对(倍增+二分)


    题目传送门(内部题108)


    输入格式

      输入文件第一行为两个正整数$n,M$。
      接下来两行,第一行为$n$个正整数$a_1sim a_n$,其中$a_i$表示编号为$i$的男生的实力值;第二行为$n$个正整数$b_1sim b_n$,其中$b_i$表示编号为$i$的女生的实力值。


    输出格式

      输出一个整数,为最少的小组数量。输入数据保证至少存在一种满足分组规则的分组方式。


    样例

    样例输入:

    3 50
    6 7 2
    6 3 5

    样例输出:

    2


    数据范围与提示

      对于$10\%$的数据,满足$nleqslant 10$。
      对于$30\%$的数据,满足$nleqslant 1,000$。
      对于$50\%$的数据,满足$nleqslant 10,000$。
      对于$70\%$的数据,满足$nleqslant 100,000$。
      对于$100\%$的数据,满足$nleqslant 500,000,1leqslant a_i,b_ileqslant 100,000,1leqslant Mleqslant 10^{15}$。


    题解

    先来考虑一种接近正解的做法,对于当前的左端点,二分右端点的位置,然后$judge$。

    但是算一算时间复杂度发现并不对,最极限的数据就是每一组都只有一个人,那么时间复杂度就是$Theta(n^2log^2n)$的了。

    考虑优化,可以先利用倍增求出范围,即为如果$l+2^p$可以,但是$l+2^{p+1}$不可以,然后再在这段区间内进行二分即可。

    因为无论是倍增还是二分,都只将整个序列$judge$了$k$遍,这里$k$只是一个很小的常数,所以复杂度就是对的了。

    注意不要被$a_i,b_i$的值域迷惑,千万不要使用桶排,因为对于这种算法,桶排的时间复杂度还是$Theta(n^2log^2n)$级别的。

    时间复杂度:$Theta(nlog^n)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    long long M;
    int a[500001],b[500001],qa[500001],qb[500001];
    int ans;
    bool judge(int l,int r)
    {
    	long long res=0;
    	for(int i=l;i<=r;i++){qa[i]=a[i];qb[i]=b[i];}
    	sort(qa+l,qa+r+1);sort(qb+l,qb+r+1);
    	for(int i=l;i<=r;i++){res+=1LL*qa[i]*qb[i];if(res>M)return 0;}
    	return 1;
    }
    int main()
    {
    	scanf("%d%lld",&n,&M);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&a[i]);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&b[i]);
    	int now=1;
    	while(now<=n)
    	{
    		ans++;
    		int lft=0,rht=0,res=now;
    		while(1)
    		{
    			if(now+(1<<rht)>n)break;
    			if(!judge(now,now+(1<<rht)))break;
    			lft=rht;rht++;
    		}
    		lft=now+(1<<lft);
    		rht=min(now+(1<<rht),n);
    		while(lft<=rht)
    		{
    			int mid=(lft+rht)>>1;
    			if(judge(now,mid)){lft=mid+1;res=mid;}
    			else rht=mid-1;
    		}
    		now=res+1;
    	}
    	nxt:;
    	printf("%d",ans);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    golang并发
    golang接口
    golang方法
    golang函数
    微信小程序请求封装
    使用vue实现打印功能时出现多余空白页的问题
    mybatis 基本配置
    sql调优
    触发器 索引
    收藏 故事形式讲解javaScript中创建对象和Java创建对象的区别
  • 原文地址:https://www.cnblogs.com/wzc521/p/11775352.html
Copyright © 2020-2023  润新知