P1912 [NOI2009]诗人小G

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;
}

 

转载于:https://www.cnblogs.com/widsom/p/10949454.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值