把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷1912】[NOI2009] 诗人小G(决策单调性优化DP)

点此看题面

  • 给定\(n\)个诗句,你可以把若干连续的诗句并在一行(一行的诗句间要加空格)。
  • 给定一个标准值\(m\)和一个数\(p\),要求最小化每行字数和\(m\)之差的绝对值的\(p\)次方和。
  • 数据组数\(\le5,n\le10^5,p\le10\)

暴力\(DP\)

显然\(DP\)时我们不需要考虑诗句内容,只要知道其长度即可。

\(a_i\)为诗句长度的前缀和,\(f_i\)为考虑了前\(i\)个诗句时的最优答案,显然有暴力\(DP\)

\[f_i=\min_{j=0}^{i-1}\{f_j+|a_i-a_j+i-j-1-m|^p\} \]

其中\(i-j-1\)表示需要增加的空格数。

决策单调性

不妨设\(Calc(j,i)\)为从\(j\)转移向\(i\)的代价,也就是\(|a_i-a_j+i-j-1-m|^p\)

显然这个东西不太好拆,很难斜率优化。

所以我们考虑决策单调性

突然发现自己竟从未写过决策单调性优化\(DP\)这种神奇的东西。。。

对于这道题,我们开一个单调队列,并记下队列中每两个元素之间的决策分界点\(k\),表示在\(k\)之前从前一个元素转移,在\(k\)之后从后一个元素转移。

显然这个单调队列需要满足\(k\)递增。

至于如何求出\(k\),每次要新计算两个元素之间的决策层分界点时,直接二分即可。

代码:\(O(nlogn)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define DB long double
using namespace std;
int n,m,p,a[N+5],S[N+5];char s[N+5][50];
I DB QP(DB x,RI y) {DB t=1;W(y) y&1&&(t*=x),x*=x,y>>=1;return t;}
namespace Monotonicity
{
	#define Calc(j,i) (f[j]+QP(abs(a[i]-a[j]+(i)-(j)-1-m),p))//从j转移到i的代价
	int k[N+5],q[N+5],g[N+5];DB f[N+5];
	I int K(CI x,CI y)//二分分界点
	{
		RI l=y+1,r=n+1,mid;W(l^r) mid=l+r>>1,Calc(x,mid)>=Calc(y,mid)?r=mid:l=mid+1;return r;
	}
	I void DP()//决策单调性优化动态规划
	{
		RI i,H=1,T=1;for(q[1]=0,i=1;i<=n;++i)
		{
			W(H^T&&k[H]<=i) ++H;f[i]=Calc(q[H],i),g[i]=q[H];//取队首转移,记下决策点方便输出方案
			W(H^T&&k[T-1]>=K(q[T],i)) --T;k[T]=K(q[T],i),q[++T]=i;//往队尾加点,维护分界点单调性
		}
	}
}
int main()
{
	using namespace Monotonicity;
	RI Tt,i,j,T;scanf("%d",&Tt);W(Tt--)
	{
		for(scanf("%d%d%d",&n,&m,&p),i=1;i<=n;++i) scanf("%s",s[i]+1),a[i]=a[i-1]+strlen(s[i]+1);//统计前缀和
		if(DP(),f[n]>1e18) {puts("Too hard to arrange");goto End;}printf("%.0Lf\n",f[n]);//判解过大,否则输出答案
		for(T=0,i=n;i;i=g[i]) S[++T]=i;for(i=T,j=1;i;--i) W(j<=S[i]) cout<<s[j]+1<<(" \n"[j==S[i]]),++j;//根据决策点输出方案
		End:puts("--------------------");
	}return 0;
}
posted @ 2020-11-04 09:46  TheLostWeak  阅读(75)  评论(0编辑  收藏  举报