大奖赛
大奖赛
champion.c/cpp/pas
(1s/256M)
【题目描述】
Lancelot市近期要举办大奖赛啦!住在市里的市民都十分兴奋,Morgan也不例外。他查了一下比赛的信息,发现比赛一共由N场,并且每一场的门票价格可能会不相等。Morgan留给比赛的预算是K元;他想知道,一共有多少种买票的方案,使得门票之和不超过K呢?
【输入格式】champion.in
第一行两个整数N与K,代表比赛的场数和自己的预算。
第二行N个整数Ai,代表每场比赛的门票价格。
【输出格式】champion.out
一行一个整数,代表买票的总方案数。
【样例输入】
5 1000
2000 100 500 500 1000
【样例输出】
8
【数据范围与约束】
对于30%的数据,N<=10.搜索
对于60%的数据,K<=10,000.背包
对于100%的数据,1<=N<=40, 0<K,Ai<=1,000,000,000.折半搜索
折半搜索的目的就是降低时间复杂度。
把N分成两半,分开搜索,单独的时间复杂度大约是2^20 左右。
然后把 A组的排个序, 每得到一个B组中的元素,就看看能和A中元素组成几个新的。
背包写法
#include<iostream> #include<cstdio> #include<algorithm> #include<queue> #include<cstring> using namespace std; const int N=10000; int a[50]; int f[20000]; int n,k; int main() { freopen("champion.in","r",stdin); freopen("champion.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); f[0]=1; for(int i=1;i<=n;i++) for(int j=k;j>=a[i];j--) f[j]+=f[j-a[i]]; long long ans=0; for(int i=0;i<=k;i++) ans+=f[i]; cout<<ans; return 0; }
折半
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int N=45; const int S=(1<<20)+11; int n,k; int a[N],pa; int b[N],pb; int c[S],cnt; long long ans=0; void dfs(int x,int y) { if(y>k) return ; if(x==pa) { c[cnt++]=y; return ; } dfs(x+1,y);dfs(x+1,y+a[x]); } void dfs2(int x,int y) { if(y>k) return ; if(x==pb) { ans+=upper_bound(c,c+cnt,k-y)-c; return ; } dfs2(x+1,y);dfs2(x+1,y+b[x]); } int main() { freopen("champion.in", "r", stdin); freopen("champion.out", "w", stdout); scanf("%d%d",&n,&k); for(int i=0;i<n;i++) scanf("%d",&a[i]); pa=n/2;pb=n-pa; for(int i=pa;i<n;i++) b[i-pa]=a[i]; dfs(0,0); sort(c,c+cnt); dfs2(0,0); cout<<ans<<endl; return 0; }