zoukankan      html  css  js  c++  java
  • 题解 P4799 【[CEOI2015 Day2]世界冰球锦标赛】

    P4799 【[CEOI2015 Day2]世界冰球锦标赛】 (折半搜索)

    part1 40points

    暴力的40分是很好写的,直接搜就行

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #define int long long
    using namespace std;
    const int maxn=1e6;
    int n,m;
    int a[maxn];
    int ans=1;
    void dfs(int x,int la){
    	if(la-a[x]<0){
    		return ;
    	}
    	ans++;
    	for(int i=x+1;i<=n;i++){
    		dfs(i,la-a[x]);
    	}
    	return ;
    }
    signed main(){
    //	ios::sync_with_stdio(false);
    //	freopen("a.in","r",stdin);
    	cin>>n;
    	cin>>m;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    	}
    	for(int i=1;i<=n;i++){
    		dfs(i,m);
    	}
    	cout<<ans;	
    	return 0;
    }
     
    

    pasrt2 100points

    我们来考虑100分的做法,很明显,暴力是无法处理这么大的数据的我们

    来考虑对其进行优化,这里就要折半搜索了

    折半搜索是针对暴力搜索的优化算法,本质上来说就是把搜索区间分为两

    半,分开计算来优化时间复杂度,折半搜索的条件是分开搜索的结果可以

    进行合并,针对此题,我们可以将查询区间一分为二, (1- mid) , (mid+1 -n)

    分别进行暴力搜索,我们用 (a,b) 数组存储两次搜索的结果,即每个区间

    符合条件的所有花费

    最后我们将 (a) 数组从大到小排序,针对b里的每一个值 (bi),我们在a数组里查询第一个大于(m- bi)的数的下标,答案加上下标减一的值,为什么要这么做?针对有序的(a)数组,对于每一个(bi)

    我们所查找的下标减1的值就是(a)数组中与(bi)相加(<=m)的数的个数,

    所以也有这么多方案是符合题意的。

    为什么要查找第一个大于(m-bi)的数的下标?因为小于其下标的每一个值

    加上(bi)的值一定小于等于(m),但我们不知道a数组中是

    否有(m-bi),所以需要查找第一个大于它的数的下标减一,最后把答

    案加起来即可,可能听起来有点迷糊,直接看代码要清晰许多。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #define int long long
    using namespace std;
    const int maxn=5e6;
    inline int read(){
    	int f=1;
    	int ret=0;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){
    		if(ch=='-')
    			f=-f;
    		ch=getchar();
    	}	
    	while(ch<='9'&&ch>='0'){
    		ret=ret*10+(ch^'0');
    		ch=getchar();
    	}
    	return ret*f;
    }
    int n,m;
    int cnt1;
    int cnt2;
    int a[maxn];
    int b[maxn];
    int v[maxn];
    void dfs1(int id,int mx,int sum){
    	if(sum>m){
    		return ;
    	} 
    	if(id>mx){
    		a[++cnt1]=sum;
    		return ;
    	}
    	dfs1(id+1,mx,sum+v[id]);
    	dfs1(id+1,mx,sum);
    }
    void dfs2(int id,int sum){
    	if(sum>m){
    		return ;
    	}
    	if(id>n){
    		b[++cnt2]=sum;
    		return ;
    	}
    	dfs2(id+1,sum+v[id]);
    	dfs2(id+1,sum);
    }
    signed main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		v[i]=read();
    	}
    	int mid=n>>1;
    	dfs1(1,mid,0);
    	dfs2(mid+1,0);
    	sort(a+1,a+1+cnt1);
    	int ans=0;
    	for(int i=1;i<=cnt2;i++){
    		ans+=upper_bound(a+1,a+1+cnt1,m-b[i])-a-1;
    	}
    	cout<<ans;
    	return 0;
    }
    

    原本搜索的时间复杂度为 (O(2^n))

    优化为 (O(2^frac{n}{2}))

    但最后需要加上合并的时间复杂度

  • 相关阅读:
    十大排序算法之选择排序(2)
    十大排序算法之冒泡排序(1)
    2018年年度总结
    敏捷软件开发学习笔记(四)之结构型设计模式
    敏捷软件开发学习笔记(三)之创造型设计模式
    elasticsearch+head+kibana
    闭包函数延迟绑定问题
    初谈dango的post提交csrf设置和文件上传
    浏览器的同源策略,及如可跨域
    socket并发通信的几种方式
  • 原文地址:https://www.cnblogs.com/rpup/p/14061592.html
Copyright © 2011-2022 走看看