考虑把数列(w_i)重新排列,使得新数列(w_i)满足对于任意 i , 所有的 (w_{j(j<i)} + w_i geq m) 或者所有的 (w_{j(j<i)} + w_i < m,)然后(O(n^2) DP) 就容易了。
如何构造?
先把(w_i)从小到大排序。一开始答案序列(ans)为空。
如果(w_1+w_n geq m,)那么对于所有 (w_{i(i<n)},w_{i(i<n)}+w_n geq m,)可以把 (w_n) 放到(ans)的末尾,并删去 (w_n)
否则,对于所有(w_{i(i<n)},w_{i(i<n)}+w_n < m,)可以把 (w_1) 放到(ans)的末尾,并删去 (w_1)
那么就可以(O(nlog n)) 构造了。
复杂度(O(n^2))
code :
#include <bits/stdc++.h>
using namespace std;
template <typename T> void read(T &x){
static char ch; x = 0,ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
inline void write(int x){if (x > 9) write(x/10); putchar(x%10+'0'); }
const int N = 2005,P = 1e9 + 7;
int n,m,a[N];
inline void build(){
static int w[N];
int i,len = n+1,l,r;
for (i = 1; i <= n; ++i) w[i] = a[i]; sort(w+1,w+n+1);
l = 1,r = n;
while (l <= r){
if (w[l] + w[r] >= m) a[--len] = w[r],--r;
else a[--len] = w[l],++l;
}
}
inline void upd(int &x,int v){ x = (x+v>=P)?(x+v-P):(x+v); }
int mx[N][N],f[N][N];
int main(){
int i,j,v,t;
int is;
read(n),read(m);
for (i = 1; i <= n; ++i) read(a[i]);
build();
for (i = 0; i <= n; ++i) for (j = 0; j <= n; ++j) mx[i][j] = -1;
mx[1][0] = mx[1][1] = 0,f[1][0] = f[1][1] = 1;
for (i = 1; i < n; ++i){
is = a[i+1] + a[i] >= m ? 1 : 0;
for (j = 0; j <= i; ++j) if (mx[i][j] > -1){
v = f[i][j],t = mx[i][j] + is * (i-j);
if (t == mx[i+1][j+1]) upd(f[i+1][j+1],v);
else if (t > mx[i+1][j+1]) mx[i+1][j+1] = t,f[i+1][j+1] = v;
t = mx[i][j] + is * j;
if (t == mx[i+1][j]) upd(f[i+1][j],v);
else if (t > mx[i+1][j]) mx[i+1][j] = t,f[i+1][j] = v;
}
}
int Mx = 0,ans = 0;
for (i = 0; i <= n; ++i)
if (mx[n][i] > Mx) Mx = mx[n][i],ans = f[n][i];
else if (mx[n][i] == Mx) upd(ans,f[n][i]);
cout << Mx <<' ' <<ans << '
';
return 0;
}