bzoj1563: [NOI2009]诗人小G 决策单调性(1D1D)


[TOC]

#题目链接
bzoj1563: [NOI2009]诗人小G

#题解

\(n^2\) 的dp长这样
\(f_i = min(f_j + (sum_i - sum_j - 1 - L)^P)\)
设$w_ = (sum_i - sum_j - 1 - L)^P$
那么化成1D1D的标准形式
\(f_i = min(f_j + w_{i,j})\)
发现w满足四边形不等式
证明可以看这里
https://www.byvoid.com/zhs/blog/noi-2009-poet
因此状态转移方程具有单调性
#代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define gc getchar()
#define pc putchar
#define LD long double
inline int read() {
    int x = 0,f = 1;
    char c = gc;
    while(c < '0' || c > '9' )c = gc;
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc;
    return x * f ;
}
void print(LL x) {
    if(x >= 10) print(x / 10);
    pc(x % 10 + '0');
}
const int maxn = 100007; 
char s[maxn][32]; 
int n,L,p; 
inline LD fstpow(LD x,int k) { 
    LD ret = 1; 
    for(;k;k >>= 1,x = x * x) if(k & 1) ret *= x; 
    return ret; 
} 
LD f[maxn];
int sum[maxn]; 
LD calc(int j,int i) { 
    return f[j] + fstpow(std::abs(sum[i] - sum[j] - L),p); 
} 
int find(int x,int y) { 
    int l = x,r = n,ret = 0; 
    while(l <= r) { 
        int mid = l + r >> 1; 
        if(calc(x,mid) >= calc(y,mid)) r = mid - 1; 
        else l = mid + 1; 
    } 
    return l; 
} 
int q[maxn],c[maxn]; 
int pre[maxn]; 
void solve() { 
    n = read(),L = read() + 1,p = read(); 
    for(int i = 1;i <= n;++ i) { 
        scanf("%s",s[i] + 1); 
        sum[i] = sum[i - 1] + strlen(s[i] + 1) + 1; 
    } 
    int h = 1,t = 1; 
    q[h] = 0; 
    for(int i = 1;i <= n;++ i) { 
        while(h < t && c[h] <= i) ++ h;  
        f[i] = calc(q[h],i); pre[i] = q[h]; 
        while(h < t && c[t - 1] >= find(q[t],i)) t --; 
        c[t] = find(q[t],i); q[++ t] = i; 
    } 
    if(f[n] > 1e18) { 
        puts("Too hard to arrange\n--------------------"); 
        return;
    } 
    printf("%.0Lf\n", f[n]); 
     
    puts("--------------------"); 
} 
int main() { 
    int T = read();
    for(int i = 1; i <= T; ++ i) {
        solve(); 
    } 
    return 0; 
} 
posted @ 2018-10-10 21:50  zzzzx  阅读(189)  评论(0编辑  收藏  举报