1 条题解
-
0
自动搬运
来自洛谷,原作者为

浮尘ii
**搬运于
2025-08-24 21:41:32,当前版本为作者最后更新于2017-01-01 12:18:07,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
##官方题解
为了找出t和m的最大差,我们需要先找出所有可能的m,也就是要算出来有哪些数字可以通过在n个数字中挑选k个来得到。这一个简化版的01背包问题,记F[i][j][x]表示前i个数字中选出j个来,是否可以组成数字x。这样做时间复杂度是O(nkMAXB)的,可以通过85%的数据。
又可以发现F[i][j][x]全都是boolean型的,考虑把多个F[i][j][x]在最后一维进行压缩,例如我们可以用一个64位整数来表示64个boolean值。01背包的所有转移都可以用位运算来实现。这便可以通过100%的数据。
##std
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <cmath> using namespace std ; const int R = 60 ; const int MAXN = 609 ; const int MAXB = 180009 ; const int __MAXK = 13 ; int n , k , a , b , x[MAXN] , k0 , sumx[MAXN] ; long long F[MAXB][__MAXK] ; void Init() { freopen("game.in","r",stdin); freopen("game.out","w",stdout); cin >> n >> k >> a >> b ; for ( int i = 1 ; i <= n ; i ++ ) cin >> x[i] ; sumx[0] = 0 ; for ( int i = 1 ; i <= n ; i ++ ) sumx[i] = sumx[i-1] + x[i] ; } void Solve() { k0 = (k+1) / R ; if ( R * k0 < k+1 ) k0 ++ ; for ( int j = 0 ; j <= b ; j ++ ) for ( int k = 0 ; k < k0 ; k ++ ) F[j][k] = 0 ; F[0][0] = 1 ; for ( int i = 1 ; i <= n ; i ++ ) for ( int j = sumx[i] ; j >= 0 ; j -- ) for ( int k = 0 ; k < k0 ; k ++ ) { if ( k + 1 < k0 ) F[j+x[i]][k+1] |= (F[j][k] >> (R-1)) ; F[j+x[i]][k] |= (F[j][k] << 1) ; } vector<int> ans ; ans.clear() ; for ( int j = 0 ; j <= b ; j ++ ) if ( ((F[j][k0-1] >> (k+1 - R*(k0-1) - 1)) & 1) == 1 ) ans.push_back(j) ; int ret = 0 ; int near2a = abs(ans[0] - a) , near2b = abs(ans[0] - b) ; for ( int i = 1 ; i < ans.size() ; i ++ ) { if ( abs(ans[i] - a) < near2a ) near2a = abs(ans[i] - a) ; if ( abs(ans[i] - b) < near2b ) near2b = abs(ans[i] - b) ; int rr = (ans[i] - ans[i-1]) / 2 ; if ( ( a <= ans[i-1] + rr && ans[i-1] + rr <= b ) || ( a <= ans[i] - rr && ans[i] - rr <= b ) ) { if ( rr > ret ) ret = rr ; } } if ( near2a > ret ) ret = near2a ; if ( near2b > ret ) ret = near2b ; cout << ret << "\n" ; fprintf(stderr,"%d\n" , ret) ; } int main() { Init() ; Solve() ; }##C++福利
如果有个75000位的二进制数类型多好啊。
诶,STL好像有个bitset。
嗯,好像可以直接用……
##稍微跑得比std慢的AC程序
#include <iostream> #include <cstdio> #include <bitset> using namespace std; const size_t MaxN(251), MaxSum(75001); const int INF(0x7f7f7f7f); int N, K, A, B; int Xi, Sum; bitset<MaxSum> F[MaxN]; int L[MaxSum], R[MaxSum]; int Ans(-INF); int main() { freopen("game.in", "r", stdin); freopen("game.out", "w", stdout); cin >> N >> K >> A >> B; F[0].set(0); for(int i(1); i <= N; i++) { scanf("%d", &Xi); for(int j(K); j; j--) F[j] |= F[j - 1] << Xi; Sum += Xi; } L[A] = -INF; for(int i(A); ~i; i--) if(F[K][i]) { L[A] = i; break; } for(int i(A + 1); i <= B; i++) L[i] = F[K][i] ? i : L[i - 1]; R[B] = INF; for(int i(B); i <= Sum; i++) if(F[K][i]) { R[B] = i; break; } for(int i(B - 1); i >= A; i--) R[i] = F[K][i] ? i : R[i + 1]; for(int i(A); i <= B; i++) Ans = max(Ans, min(i - L[i], R[i] - i)); cout << Ans << endl; return 0; }
- 1
信息
- ID
- 1806
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者