诗人小G
诗人小G
考虑普通的 DP
。令 \(f_i\) 表示划分前 \(i\) 个句子的最小不协调度。可以用前缀和处理,易得方程 \(f_i=f_j+| s_i-s_j+i-j-1-l|^p\),注意这里空格是需要考虑长度的,也就是 \(j+1\sim i\) 成立了一段,那么应该是 \(i-(j+1)+1-1=i-j-1\) 个空格。
接下来考虑用四边形不等式优化。
首先对于那个 \(f_j\) 后面的恶心的式子就不证明了,考试时强烈建议打表。具体可以看 AcWing。接下来就是需要用到四边形不等式的性质:决策单调性,即 \(p_i\) 严格不降。我们可以用若干段区间 \([j,l,r]\) 表示这段区间 \([l,r]\) 内的决策是 \(j\)。当然这个只存储处理了前 \(i\) 个的情况。每次新加入一个数 \(i\),需要先检查队首元素的下标是否 \(\le i\),进行更新。然后是队尾,每次看这段区间的左端点的取值用 \(i\) 是否更优,如果是就删去这段区间,如果不是就看一下右端点是否用 \(i\) 更优,如果是就二分寻找中间的分界点。最后把删去的区间用 \(i\) 决策合并起来加回去。均摊是 \(O(n\log n)\)。代码有点麻烦。
#include<bits/stdc++.h>
using namespace std;
#define L(i,l,r) for(int i=l;i<=r;++i)
#define R(i,l,r) for(int i=r;i>=l;--i)
const int N=100010;
typedef long double ll;
int n,L,P,p[N],s[N],hh,tt;
ll f[N];
char str[N][31];
struct node{
int j,l,r;
}q[N];
ll val(int j,int i){
ll res=1,a=abs(s[i]-s[j]+i-j-1-L);
L(i, 1, P)res*=a;
return res+f[j];
}
void insert(int i){
int pos=n+1;
while(hh<=tt&&val(q[tt].j,q[tt].l)>=val(i,q[tt].l))pos=q[tt--].l;
if(hh<=tt&&val(q[tt].j,q[tt].r)>=val(i,q[tt].r)){
int l=q[tt].l,r=q[tt].r;
while(l<r){
int mid=(l+r)>>1;
if(val(q[tt].j,mid)>=val(i,mid))r=mid;
else l=mid+1;
}
q[tt].r=r-1;
pos=r;
}
if(pos!=n+1)q[++tt]={i,pos,n};
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
// ios::sync_with_stdio(0);
// cin.tie(0);
// cout.tie(0);
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&L,&P);
R(i, 1, n)scanf("%s",str[i]);
L(i, 1, n)s[i]=s[i-1]+strlen(str[i]);
hh=tt=0;
q[0]={0,1,n};
L(i, 1, n){
f[i]=val(q[hh].j,i),p[i]=q[hh].j;
if(q[hh].r==i)++hh;
q[hh].l=i+1;
insert(i);
}
if(f[n]>1e18)puts("Too hard to arrange");
else{
printf("%lld\n",(long long)f[n]);
for(int i=n;i;i=p[i])
R(j, p[i]+1, i)
printf("%s%c",str[j],(j==p[i]+1)?'\n':' ');
}
puts("--------------------");
}
return 0;
}