1. 程式人生 > 其它 >【模板】折半搜尋

【模板】折半搜尋

算半個模板題

某位機房大佬(折半+STL)
#include<bits/stdc++.h>
using namespace std;
long long n,m,w[101],mid,a[1<<20],b[1<<20],sum1,sum2,ans;
int dfs1(int l,long long sum){
    if(sum>m) return 0;
    if(l>mid){
        a[++sum1]=sum;
        return 0;
    }
    dfs1(l+1,sum);
    dfs1(l+1,sum+w[l]);
    
return 0; } int dfs2(int l,long long sum){ if(sum>m) return 0; if(l>n){ b[++sum2]=sum; return 0; } dfs2(l+1,sum); dfs2(l+1,sum+w[l]); return 0; } int main(){ scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&w[i]); mid=n/2
; dfs1(1,0); dfs2(mid+1,0); sort(a+1,a+1+sum1); for(int i=1;i<=sum2;i++){ int t=upper_bound(a+1,a+1+sum1,m-b[i])-a-1; ans+=t; } printf("%lld",ans); return 0; }
俺不同的做法(狀壓DP(半個)+二分)
#include<iostream>
#include<cstdio>
#include<algorithm>
using
namespace std; long long limit_1,limit_2; long long dp1[(1<<20)],dp2[(1<<20)]; long long a[10000001]; long long mid_search(long long M){ long long l=0,r=((long long)1<<(long long)limit_2)-(long long)1,ans=0; while(l<=r){ int mid=(l+r)/2; if(dp2[mid]<=M){ ans=mid; l=mid+1; } else r=mid-1; } return ans+1; } int main(){ long long n,m; scanf("%lld%lld",&n,&m); for(register int i=1;i<=n;i++) scanf("%lld",&a[i]); limit_1=(long long)n/(long long)2; limit_2=(long long)n-(long long)limit_1; for(register int i=1;i<(1<<limit_1);i++){ for(register int j=1;j<=limit_1;j++){ if(((1<<(j-1))&i)==0) continue; dp1[i]+=a[j]; } } for(register int i=1;i<(1<<limit_2);i++){ for(register int j=1;j<=limit_2;j++){ if(((1<<(j-1))&i)==0) continue; dp2[i]+=a[j+limit_1]; } } sort(dp1,dp1+(1<<limit_1)); sort(dp2,dp2+(1<<limit_2)); long long ans1=0; for(register int i=0;i<(1<<limit_1);i++){ if(dp1[i]>m) break; ans1+=mid_search(m-dp1[i]); } printf("%lld",ans1); return 0; }