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


    点此看题面

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

    暴力(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
    ",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<<(" 
    "[j==S[i]]),++j;//根据决策点输出方案
    		End:puts("--------------------");
    	}return 0;
    }
    
  • 相关阅读:
    C# 學習使用StatusStrip
    初學C#打印
    C# 學習使用ErrorProvider
    C# 字符串中增、刪、替換字符學習
    mos开发系列教程八:页面代码研究地图控件页面结构
    MapGuide open source开发系列教程五: 屏幕坐标与地图坐标(问题)已修改
    ajax学习笔记一:动态更改div位置
    mos开发系列教七:框架分析
    mos开发系列教程十:说明
    MapGuide open source开发系列教程六: 地图状态与事件(含问题)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu1912.html
Copyright © 2020-2023  润新知