LOJ#6502. 「雅礼集训 2018 Day4」Divide 题解
考虑把数列\(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(n\log 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 << '\n';
return 0;
}