#include #include #include #include #define rep(i,a,b) for(int i=(a);i<(b);i++) #define rrep(i,a,b) for(int i=(b)-1;i>=(a);i--) #define all(x) begin(x),end(x) #define sz(x) (int)(x).size() using namespace std; using namespace atcoder; using ll=long long; using ull=unsigned long long; using ld=long double; using vll=vector; using vvll=vector; using vi=vector; using vvi=vector; using pll=pair; using pi=pair; // using mint=modint998244353; using mint=modint1000000007; // using mint2=static_modint<2>; // using BoostPoint=boost::polygon::point_data; // using Voronoi=boost::polygon::voronoi_diagram; // using mint=LazyMontgomeryModInt<998244353>; using vm=vector; // using vvm=vector; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); /** * 要はF_i,F_{i+1},...,F_N任意の部分和a= F_{i-1} (1) * * c - a >= F_{i+1} (2) * * これで次のように枝刈りできます: * * 品物i,i+1,...,Nのみ使える時、価値の最大値をB、任意の部分和をvとして * * 明らかに v + \sum_{j=1}^{i-1} F_j < B のような v は捨てれば良い * * 残された v は必ず B - F_{i+1} + 2 <= v <= B ので (ここは\sum_{j=1}^{i-1} F_j = F_{i+1} - 2を使います) * * (2)よりこのような v は高々2個しか存在しない */ int T,N; cin>>T; ll F[76]={0,1,2},S[76]={}; rep(i,3,76)F[i]=F[i-1]+F[i-2]; rep(i,1,76)S[i]=S[i-1]+F[i]; while(T--){ ll W; cin>>N>>W; vll w(N+1); rep(i,1,N+1)cin>>w[i]; vectordp={{0,0}}; rrep(i,1,N+1){ vectorndp=dp; for(auto&[v,tw]:dp){ if(tw+w[i]<=W)ndp.push_back({v+F[i],tw+w[i]}); } sort(all(ndp)); ll B=ndp.back().first; dp.clear(); for(auto&[v,tw]:ndp){ if(v+S[i-1]