[NOI2009]诗人小G(决策单调性优化dp)

【题解】

经典的1D1D动态规划优化 

状态转移方程:f[i]=min{ f[j]+abs(s[i]-s[j]+i-j-1-l)^p } 

决策单调性及证明:
http://blog.csdn.net/jasonzhu8/article/details/5928552

因此,对于每个数,其能作为最优决策的区间一定是连续的一段,
对于新求出的f[i],从后往前在i-1,i-2,…对应的决策区间内二分查找 i的决策区间
用一个栈去维护每个数对应的决策区间即可 

此题f值巨大,需先用double计算,判断答案是否小于10^18,如果是,在用long long算一遍(double精度不够)


【代码】

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define INF 1000000000000000000ll
typedef long long LL;
char poem[100005][35];
double s[100005],f[100005];
int sta[100005],L[100005],R[100005],id[100005],from[100005];
int n,p,l,ps;
int max(int a,int b)
{
	if(a>b) return a;
	return b;
}
double jdz(double x)
{
	if(x<0) x=-x;
	return x;
}
LL jdz_L(LL x)
{
	if(x<0) x=-x;
	return x;
}
double W(int j,int i)
{
	double a=jdz(s[i]-s[j]+i-j-1-(double)l),ans=1;
	int k;
	for(k=1;k<=p;k++)
		ans*=a;
	return ans;
}
LL W_L(int j,int i)
{
	LL a=jdz_L((LL)s[i]-(LL)s[j]+(LL)i-(LL)j-1-(LL)l),ans=1;
	int k;
	for(k=1;k<=p;k++)
		ans*=a;
	return ans;
}
void jiaru(int k)
{
	int left,mid,right,i;
	for(;ps>0;ps--)
	{
		left=max(L[ps],k+1);
		if(f[k]+W(k,left)<=f[sta[ps]]+W(sta[ps],left))
		{
			if(L[ps]<=k+1)
			{
				if(L[ps]==k+1) ps--;
				else R[ps]=k;
				sta[++ps]=k;
				L[ps]=k+1;
				R[ps]=n;
				id[k+1]=k;
				return;
			}
		}
		else
		{
			right=R[ps];
			while(left<right)//左闭右开区间 
			{
				mid=(left+right+1)/2;
				if(f[k]+W(k,mid)<=f[sta[ps]]+W(sta[ps],mid)) right=mid-1;
				else left=mid;
			}
			if(left==n) return;
			R[ps]=left;
			sta[++ps]=k;
			L[ps]=left+1;
			R[ps]=n;
			id[left+1]=k;
			return;
		}
	}
}
LL get(int k)
{
	if(k==0) return 0;
	return get(from[k])+W_L(from[k],k);
}
void print(int k)
{
	int i;
	if(k==0) return;
	print(from[k]);
	for(i=from[k]+1;i<=k;i++)
	{
		printf("%s",poem[i]);
		if(i<k) printf(" ");
	}
	printf("\n");
}
int main()
{
	int T,i,j;
	scanf("%d",&T);
	for(;T>0;T--)
	{
		memset(poem,0,sizeof(poem));
		memset(s,0,sizeof(s));
		memset(id,0,sizeof(id));
		memset(from,0,sizeof(from));
		scanf("%d%d%d",&n,&l,&p);
		for(i=1;i<=n;i++)
		{
			scanf("%s",poem[i]);
			s[i]=(double)strlen(poem[i])+s[i-1];
		}
		sta[ps=1]=0;
		L[ps]=1;
		R[ps]=n;
		j=0;
		for(i=1;i<=n;i++)
		{
			if(j<id[i]) j=id[i];
			f[i]=f[j]+W(j,i);
			from[i]=j;
			jiaru(i);
		}
		if(f[n]>INF) printf("Too hard to arrange\n");
		else
		{
			printf("%lld\n",get(from[n])+W_L(from[n],n));
			print(n);
		}
		printf("--------------------\n");
	}
	return 0;
}


你可能感兴趣的:(NOI,1D1D动态规划)