题目描述
题解
数据太大了中间要用long double
显然每一个句子只有长度是有价值的
令
f(i)
表示前i个句子放好的最小不协调度
裸dp
O(n2)
还是需要优化
记录一下决策发现有单调性
但是这道题
f(i)
需要从
f(j)
转移过来
转一个图 地址:http://www.bubuko.com/infodetail-225479.html
加一个双向链表或者数据结构也行?
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define LL long long
#define N 100005
const long double inf=1e18;
int T,n,P,pos[N],pre[N],nxt[N];
char word[50];
long double L,a[N],s[N],f[N];
long double fast_pow(long double a,int p)
{
long double ans=1.0;
if (a<0) a=-a;
for (;p;p>>=1,a*=a)
if (p&1)
ans*=a;
return ans;
}
long double calc(int i,int j)
{
return f[j]+fast_pow(s[i]-s[j]+(long double)i-(long double)j-1.0-L,P);
}
bool check(int mid,int x,int y)
{
long double p=calc(mid,x);
long double q=calc(mid,y);
return p>=q;
}
int find(int l,int r,int x,int y)
{
int mid,ans=n+1;
while (l<=r)
{
mid=(l+r)>>1;
if (check(mid,x,y)) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
int main()
{
scanf("%d",&T);
while (T--)
{
cin>>n>>L>>P;
for (int i=1;i<=n;++i)
{
scanf("%s",word);
a[i]=(long double)strlen(word);s[i]=s[i-1]+a[i];
}
for (int i=0;i<=n;++i) f[i]=inf+1,pos[i]=n+1;
for (int i=0;i<=n;++i) pre[i]=i-1,nxt[i]=i+1;
f[0]=0;pos[0]=1;
int now=0;
for (int i=1;i<=n;++i)
{
while (pos[nxt[now]]<=i)
now=nxt[now];
long double p=calc(i,now);
f[i]=min(f[i],p);
while (pos[pre[i]]>i)
{
if (check(pos[pre[i]],pre[i],i))
{
pre[i]=pre[pre[i]];
nxt[pre[i]]=i;
}
else break;
}
pos[i]=find(pos[pre[i]],n,pre[i],i);
if (pos[i]>n) nxt[pre[i]]=nxt[i],pre[nxt[i]]=pre[i];
}
if (f[n]>inf) puts("Too hard to arrange");
else cout<<(long long)f[n]<<endl;
puts("--------------------");
}
}