您的位置:首页 > 其它

[BZOJ1563][NOI2009]诗人小G(dp+决策单调性)

2017-02-26 11:36 337 查看

题目描述

传送门

题解

数据太大了中间要用long double

显然每一个句子只有长度是有价值的

令f(i)表示前i个句子放好的最小不协调度

裸dpO(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
,pre
,nxt
;
char word[50];
long double L,a
,s
,f
;

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
>inf) puts("Too hard to arrange");
else cout<<(long long)f
<<endl;
puts("--------------------");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: