这算是决策单调性入门题吧.
我们很容易发现 $f[i]$ 的转移 $p_{i}$ 满足单调性,然后拿单调队列来维护就行.
- 对于队列中每个元素维护这个元素转移区间的右端点
- 新加入一个点的时候和队尾比较一下,看队尾是否会被覆盖,弹掉无用元素.
code:
#include <bits/stdc++.h>
#define ll long long
#define N 100009
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,L,P,s[N],q[N],k[N],pr[N];
long double f[N];
char str[N][33];
long double qpow(long double x)
{
long double tmp=1;
for(int k=P;k;k>>=1,x*=x)
if(k&1) tmp*=x;
return tmp;
}
long double calc(int i,int j) { return f[j]+qpow(abs(s[i]-s[j]-L)); }
int find(int x,int y)
{
if(calc(n,x)<=calc(n,y))
return n+1;
int l=y,r=n+1,mid,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
if(calc(mid,x)>=calc(mid,y))
ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
void solve()
{
scanf("%d%d%d",&n,&L,&P),++L;
for(int i=1;i<=n;++i)
{
if(scanf("%s",str[i]));
s[i]=s[i-1]+strlen(str[i])+1;
}
int h=1,t=1;
q[h]=0;
for(int i=1;i<=n;++i)
{
while(h<t&&k[h]<=i) ++h;
f[i]=calc(i,q[h]),pr[i]=q[h];
while(h<t&&k[t-1]>=find(q[t],i)) --t;
k[t]=find(q[t],i),q[++t]=i,k[t]=n+1;
}
if(f[n]>1e18) printf("Too hard to arrange\n");
else
{
printf("%.0Lf\n",f[n]);
}
puts("--------------------");
}
int main()
{
// setIO("input");
int T;
scanf("%d",&T);
while(T--) solve();
return 0;
}