世界冰球锦标赛题解
世界冰球锦标赛题解
折半搜索裸题
我们可以先枚举前一半的所有方案,总共有\(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;
}