世界冰球锦标赛题解

世界冰球锦标赛题解

折半搜索裸题

我们可以先枚举前一半的所有方案,总共有\(2^{20}=1048576\approx 1000000\)种,

(注意数组大小要大于1048576,作者第一次提交就只开了1000000,锅了

用一个数组c储存并排序。

在枚举后一半的方案,设其费用为w,

按w从大到小排序,

用一个单调指针维护c数组中小于等于m-w的方案个数,

ans累加方案个数。

(w从大到小,m-w从小到大,指针单调右移)

当然你也可以离散化后用前缀和(太麻烦了,不写),

或者排序后用upper_bound(多此一举

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e6+6;
int l=1,n1,n2,n,num1=0,num2=0;
ll t,m,ans=0,a[N],b[N],c[N],d[N];
inline ll read(){
   ll T=0,F=1; char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
   while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
   return F*T;
}
void dfs(int x,ll y,int z,ll p[],ll q[],int &num){
     if(y>m) return;
     if(x>z){p[++num]=y; return;}
     dfs(x+1,y,z,p,q,num),dfs(x+1,y+q[x],z,p,q,num);
}
int main(){
    n=read(),m=read(),n1=(n>>1),n2=n-n1;
    for(int i=1;i<=n1;++i) a[i]=read();
    for(int i=1;i<=n2;++i) b[i]=read();
    dfs(1,0,n1,c,a,num1),sort(c+1,c+num1+1);
    dfs(1,0,n2,d,b,num2),sort(d+1,d+num2+1);
    for(int i=num2;i>=1;--i){
        t=m-d[i];
        while(l<=num1&&c[l]<=t) ++l;
        ans+=1ll*(l-1);
    } 
    printf("%lld\n",ans);
    return 0;
} 
posted @ 2019-08-08 19:13  lsoi_ljk123  阅读(161)  评论(0编辑  收藏  举报