LOJ#6502. 「雅禮集訓 2018 Day4」Divide 題解
阿新 • • 發佈:2020-09-07
考慮把數列\(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,\)
那麼就可以\(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; }