您的位置:首页 > 其它

【bzoj1563】 [NOI2009]诗人小G

2016-06-21 20:15 302 查看
题目

n^2的转移方程很容易想到:

f[i]=min(f[j]+(sum[i]-sum[j]+i-j-1)^p)

因为sum单调递增,p>=2,很显然具有决策单调性,用单调栈维护每个决策点覆盖的区间,

更新时在单调栈里二分找到当前最优的决策点并覆盖到n的区间。

复杂度nlogn

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>

#define maxn 100010

using namespace std;

inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret;
}

long double f[maxn];
int n,m,sum[maxn],p,l[maxn],r[maxn],q[maxn],tail,head;
char s[50];

long double Qpow(long double x)
{
int y=p;long double ret=1;
while(y){
if(y&1) ret=ret*x;
x=x*x;
y>>=1;
}
return ret;
}

long double cal(int x,int y)
{
return f[x]+Qpow(abs(sum[y]-sum[x]+y-x-1-m));
}

void update(int x)
{
while(l[tail]>x&&cal(x,l[tail])<cal(q[tail],l[tail])){
r[tail-1]=r[tail];tail--;
}
int L=l[tail],R=r[tail],pos=R+1;
while(L<=R){
int mid=L+R>>1;
if(cal(x,mid)<cal(q[tail],mid)){
pos=mid,R=mid-1;
}else L=mid+1;
}
if(pos<=r[tail]){
r[tail+1]=r[tail],l[tail+1]=pos;
q[tail+1]=x;
r[tail]=pos-1,tail++;
}
}

void dp()
{
head=tail=1;
l[1]=1,r[1]=n;
for(int i=1;i<=n;i++){
while(r[head]<i&&head<=tail) head++;
f[i]=cal(q[head],i);
update(i);
}
}

void init()
{
n=read(),m=read(),p=read();
for(int i=1;i<=n;i++){
scanf("%s",s);
sum[i]=sum[i-1]+strlen(s);
}
dp();
if(f
>1e18) puts("Too hard to arrange");
else printf("%lld\n",(long long)f
);
puts("--------------------");
}

int main()
{
int T=read();
while(T--){
init();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: