传送门:(涉及版权忽略)
【题解】
我们发现n的范围很小,提示我们可以折半,然后我们就会了O(T2^(n/2)*n)的做法,然而会T。
考虑如何优化。直接排序会多一个log(2^(n/2))也就是n,那么改成每次加一个数,归并即可。这样复杂度是对的
T(n) = T(n-1) + 2^n ==> T(n) = O(2^n)
那么复杂度就是O(T2^(n/2))
# include <stdio.h> # include <string.h> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 50 + 10, N = 2333333; const int mod = 1e9+7; # define FO_OPEN 0 # define RG register # define ST static int n, m, a[M]; int c[2][N], cn[2]; int t[N]; inline void merge(int pos, int l, int mid, int r) { int i = l, j = mid+1, k = l-1; while(i<=mid && j<=r) { if(c[pos][i] < c[pos][j]) t[++k] = c[pos][i++]; else t[++k] = c[pos][j++]; } while(i<=mid) t[++k] = c[pos][i++]; while(j<=r) t[++k] = c[pos][j++]; for (int o=l; o<=r; ++o) c[pos][o] = t[o]; } inline void sol() { int sum = 0; scanf("%d%d", &n, &m); for (int i=1; i<=n; ++i) scanf("%d", &a[i]), sum = sum + a[i]; if(sum < m) { puts("-1"); return ; } int res = n/2; c[0][cn[0] = 1] = 0; for (int i=1; i<=res; ++i) { for (int j=1; j<=cn[0]; ++j) c[0][j+cn[0]] = c[0][j] + a[i]; merge(0, 1, cn[0], cn[0] << 1); cn[0] <<= 1; } // printf("cn[0] = %d ", cn[0]); // for (int i=1; i<=cn[0]; ++i) printf("%d ", c[0][i]); // puts(" ===================="); c[1][cn[1] = 1] = 0; for (int i=res+1; i<=n; ++i) { for (int j=1; j<=cn[1]; ++j) c[1][j+cn[1]] = c[1][j] + a[i]; merge(1, 1, cn[1], cn[1] << 1); cn[1] <<= 1; } // printf("cn[1] = %d ", cn[1]); // for (int i=1; i<=cn[1]; ++i) printf("%d ", c[1][i]); // puts(""); int p0 = 1, p1 = cn[1], ans = 2147483647; for (; p0 <= cn[0]; p0 ++) { while(p1 && c[0][p0] + c[1][p1] >= m) --p1; if(p1 != cn[1]) ans = min(ans, c[0][p0] + c[1][p1 + 1]); } printf("%d ", ans); } int main() { FO_OPEN ? freopen("challenge.in", "r", stdin), freopen("challenge.out", "w", stdout) : 0; int T; scanf("%d", &T); while(T--) sol(); return 0; }