P1912 [NOI2009]诗人小G
思路:
平行四边形不等式优化dp
因为f(j, i) = abs(sum[i]-sum[j]+i-j-1-l)^p 满足平行四边形不等式
j < i
f(j, i+1) + f(j+1, i) >= f(j, i) + f(j+1, i+1)
所以dp[i]具有决策单调性
代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> using namespace std; #define y1 y11 #define fi first #define se second #define pi acos(-1.0) #define LL long long #define LD long double //#define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pli pair<LL, int> #define pii pair<int, int> #define piii pair<int, pii> #define pdd pair<long double, long double> #define mem(a, b) memset(a, b, sizeof(a)) #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout); //head const int N = 1e5 + 5; const LL UP = 1e18; string s[N]; int T, n, l, p, sum[N], pre[N]; LD dp[N]; vector<int> vc; struct Node { int l, r, j; }; deque<Node> q; inline LD Pow(int x) { LD res = 1; for (int i = 1; i <= p; ++i) res *= x; return res; } inline LD cal(int j, int i) { return dp[j] + Pow(abs(sum[i]-sum[j]+i-j-1-l)); } inline int srch(int l, int r, int i, int j) { int m = l+r >> 1; while(l < r) { if(cal(i, m) <= cal(j, m)) r = m; else l = m+1; m = l+r >> 1; } return m; } int main() { fio; cin >> T; while(T--) { cin >> n >> l >> p; for (int i = 1; i <= n; ++i) cin >> s[i]; for (int i = 1; i <= n; ++i) sum[i] = sum[i-1] + s[i].size(); while(!q.empty()) q.pop_back(); q.push_back({1, n, 0}); dp[0] = 0; for (int i = 1; i <= n; ++i) { if(q.front().r == i-1) q.pop_front(); else q.front().l = i; pre[i] = q.front().j; dp[i] = cal(q.front().j, i); int pos = -1; while(!q.empty()) { if(cal(i, q.back().l) <= cal(q.back().j, q.back().l)) { pos = q.back().l; q.pop_back(); } else { if(cal(i, q.back().r) <= cal(q.back().j, q.back().r)) { pos = srch(q.back().l, q.back().r, i, q.back().j); q.back().r = pos-1; q.push_back({pos, n, i}); } else { if(~pos) q.push_back({pos, n, i}); break; } } } } if(dp[n] > UP) cout << "Too hard to arrange\n"; else { cout <<fixed<<setprecision(0)<< dp[n] << "\n"; int now = n; while(now) { vc.pb(now); now = pre[now]; } vc.pb(0); reverse(vc.begin(), vc.end()); for (int i = 1; i < vc.size(); ++i) { for(int j = vc[i-1]+1; j <= vc[i]; ++j) { cout << s[j]; if(j != vc[i]) cout << " "; else cout << "\n"; } } vc.clear(); } cout << "--------------------\n"; } return 0; }