首先肯定是将老鼠和洞都排好序, dp[ i ][ j ] 表示处理了 前 i 个洞, 进去 j 只老鼠的最小距离和, 很明显处理先处理靠前的老鼠。
然后观察一下这个dp, 发现它满足决策单调性, 然后直接上了个分治, 然后 T 了。
然后继续观察了半天, 发现对于, dp[ i - 1 ][ 0 ], dp[ i - 1 ][ 1 ], dp[ i - 1 ][ 2 ] .... 这些值转移到dp[ i ][ j - 1 ] 和 dp[ i ][ j ]有啥区别,
发现加入最后一只老鼠对所有的值的贡献都是一样的, 然后就能用单调队列维护这个东西了。
其实决策单调也能过, 不过是我写的太挫了(逃
#include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 5000 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;} int n, m, x[N]; PII hole[N]; LL dp[2][N]; LL sufadd[N]; LL *f = dp[0], *g = dp[1]; int main() { scanf("%d%d", &n, &m); int sum = 0; for(int i = 1; i <= n; i++) scanf("%d", &x[i]); for(int i = 1; i <= m; i++) scanf("%d%d", &hole[i].fi, &hole[i].se), sum += hole[i].se; if(sum < n) return puts("-1"), 0; sort(x + 1, x + 1 + n); sort(hole + 1, hole + 1 + m); memset(f, INF, N * sizeof(LL)); f[0] = 0; int nowcnt = 0, precnt = 0; deque<int> que; for(int i = 1; i <= m; i++) { swap(f, g); while(!que.empty()) que.pop_back(); nowcnt += hole[i].se; memset(f, INF, N * sizeof(LL)); for(int j = min(n, nowcnt); j >= 0; j--) sufadd[j] = sufadd[j + 1] + abs(x[j] - hole[i].fi); for(int j = 0; j <= min(n, nowcnt); j++) { if(j <= precnt) { while(!que.empty() && g[que.back()] + sufadd[que.back() + 1] >= g[j] + sufadd[j + 1]) que.pop_back(); que.push_back(j); } while(!que.empty() && que.front() < j - hole[i].se) que.pop_front(); f[j] = g[que.front()] + sufadd[que.front() + 1] - sufadd[j + 1]; } precnt += hole[i].se; } printf("%lld ", f[n]); return 0; } /* */