特別鳴謝
由孟神糾正出的一個錯別字,現已更正。
特別提示:膜孟神能有特殊BUFF加成。
題解中涉及大佬的博客
題目描述
譯自 CEOI2015 Day2 T1「Ice Hockey World Championship」
今年的世界冰球錦標賽在捷克舉行。Bobek 已經抵達布拉格,他不是任何團隊的粉絲,也沒有時間觀念。他只是單純的想去看幾場比賽。如果他有足夠的錢,他會去看所有的比賽。不幸的是,他的財產十分有限,他決定把所有財產都用來買門票。
給出 Bobek 的預算和每場比賽的票價,試求:如果總票價不超過預算,他有多少種觀賽方案。如果存在以其中一種方案觀看某場比賽而另一種方案不觀看,則認爲這兩種方案不同。
輸入格式
第一行,兩個正整數 N 和 ,表示比賽的個數和 Bobek 那家徒四壁的財產。
第二行,N 個以空格分隔的正整數,均不超過 ,代表每場比賽門票的價格。
輸出格式
輸出一行,表示方案的個數。由於 NN 十分大,注意:答案 。
輸入輸出樣例
輸入
5 1000
100 1500 500 500 1000
輸出
8
說明/提示
樣例解釋
八種方案分別是:
一場都不看,溜了溜了
價格100的比賽
第一場價格500的比賽
第二場價格500的比賽
價格 100 的比賽和第一場價格 500的比賽
價格 100 的比賽和第二場價格 500的比賽
兩場價格 500的比賽
價格 1000 的比賽
有十組數據,每通過一組數據你可以獲得 10 分。各組數據的數據範圍如下表所示:
數據組號 1-21−2 3-43−4 5-75−7 8-108−10
10 | 20 | 40 |40
這題在不是很相信洛谷上是紫題,畢竟很快就想出來了。
當然還是得益於大佬提點我的那句:爆搜。
機房有一大佬,一日與不知何處的小學弟QQ上交流,學弟給出一題:現有一揹包,揹包有一承重W
有n個物品,物品有重量,求裝揹包的方案數 。
對,就是這道題改了下描述。
當日,大佬說題難度普及,要我與其同思其解,幫學弟解疑答惑。
我信了題目的鬼,深以爲是揹包dp,思良久不得解。
忽另一大佬路過,聽其題意後,戲笑而說:爆搜。
吾思之,N若爲20,尚可枚舉,今有40,不可枚舉。
忽靈光一閃至,爲何不從兩邊搜,一邊搜20,複雜度豈不可過?
搜兩次,統計方法答案爲何?
可若第二次搜完時枚舉第一次狀態判斷合法否,複雜度仍爲,吾休矣。
這時大佬突然對我施以援手:記錄第一次搜的狀態,排序,二分查找。
感激甚,大佬無愧於大佬,救人於水深火熱之中,如菩薩降臨,帶衆生脫離苦海。
好,
第一次搜時用a數組存下合法狀態,即每次搜完後合法的門票價錢和。
對存下的狀態進行遞增排序
第二次時,對於每一個搜完的合法狀態,我們記選擇的門票爲;前一次搜出的狀態爲
那麼和並狀態時,合併合法的條件是 變一下就是
我們剛剛對a數組進行了排序,那麼我們就可以找到第一個大於的數,這個數前面的數都是合法的,
那麼合法的就有改數下標-1個,直接加到答案中去即可。
這樣的話我們的複雜度就是
此題可過矣。
#include<bits/stdc++.h>
#define ll long long
#define MAXN 500010
#define N 201
#define INF 0x3f3f3f3f
#define gtc() getchar()
using namespace std;
template <class T>
inline void read(T &s){
s = 0; T w = 1, ch = gtc();
while(!isdigit(ch)){if(ch == '-') w = -1; ch = gtc();}
while(isdigit(ch)){s = s * 10 + ch - '0'; ch = gtc();}
s *= w;
}
template <class T>
inline void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x/10);
putchar(x % 10 + '0');
}
int n;
ll m;
ll w[MAXN];
ll a[1 << 21], cnt = 0;
int mid;
void dfs(int x, ll ans){//枚舉前一半
if(ans > m) return ;//剪枝
if(x > mid){
a[++cnt] = ans;
return ;
}
// printf("%d %d\n", x , ans);
dfs(x+1, ans);
dfs(x+1, ans + w[x]);
}
ll ans = 0;
void dfs2(int x, ll num){//枚舉後一半
if(num > m) return ;//剪枝
if(x > n){//搜完後二分查找
int tx = upper_bound(a+1, a+cnt+1, m - num) - a - 1;
ans += tx;//累加答案
return ;
}
dfs2(x+1, num);
dfs2(x+1, num+w[x]);
}
int main()
{
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
read(n), read(m);
mid = n >> 1;
for(int i = 1; i <= n; ++i) read(w[i]);
dfs(1, 0);
sort(a + 1, a + cnt + 1);
dfs2(mid + 1, 0);
cout << ans << endl;
return 0;
}