• 决策单调性总结


    决策单调性,通常用于(1d/1d)
    就是说,对于任意(a<b<c<d),若满足在c处转移到b比a优,那么在d处也满足。
    另外一种理解:转移决策点单调不降。
    证明:主要靠打表。
    得到这个性质后,我们有两种方法:

    1、分治法

    每次取分治区间的中点,并暴力在可行区间内找到它的最优转移位置。
    之后,根据这个位置,分治两边的位置,并缩小可行区间的范围。
    时间复杂度:(O(nlogn))
    并且,它满足一个性质:若转移点为((l,r)),那么(l,r)的移动距离之和为(O(nlogn)),即均摊(O(1)),有时可以用类似莫队的方法。
    优点:好写,好理解,并且找转移位置是连续寻找的,有的问题会比较方便。
    缺点:要求dp之间没有依赖(即没有计算顺序的要求),比如多阶段dp。

    2、二分+双端队列法

    我们按照顺序进行dp,并维护每个位置当前状态下的最优转移位置。
    当计算到(i)时:
    首先,算出(dp(i))
    其次,算出用它转移的区间。根据定义,只要找到第一个用(i)转移比当前更优的位置,那么之后的都是由它转移更优。
    这个位置可以使用二分查找。
    因此,我们需要实现后缀覆盖,(O(1))单点查询。似乎不容易。
    由于后缀覆盖具有均摊性,我们考虑维护转移位置相同的若干段。
    维护一个队列,每个节点记录它对应的区间,和转移位置。
    在二分查找时,我们从队尾反向遍历,并在这个区间内二分查找,若找不到,则退出。否则,把这个从队尾扔出。
    若没有完全覆盖,则把这个区间缩小。最后,在队尾加入当前区间。

    注意:
    1、在依次计算dp时,要把队首没用的弹出。
    2、在二分查找时,左端点要和(i+1)(max)
    3、要特判(i)不能更新任何位置的情况。

    优点:适用情况更普遍,比如诗人小G
    缺点:细节较多,难以理解,相对难写。

    刚才那题的代码:

    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #define max(a,b) a>b?a:b
    #define ld long double
    ld dp[100010];
    ld ksm(ld a,int b)
    {
    	ld jg=1;
    	while(b>0)
    	{
    		if(b&1)
    			jg*=a;
    		a*=a;b=(b>>1);
    	}
    	return jg;
    }
    char zf[100010][31];
    int he[100010],wz[100010],st[100010],l,p;
    ld cal(int i,int j)
    {
    	return dp[j]+ksm(fabs((he[i]-he[j]-1)-l),p);
    }
    struct SJd
    {
    	int l,r,z;
    	SJd(){}
    	SJd(int L,int R,int Z)
    	{
    		l=L;r=R;z=Z;
    	}
    };
    SJd dl[200010];
    int efcz(int l,int r,int x,int y)
    {
    	while(l<r)
    	{
    		int m=(l+r)>>1;
    		if(cal(m,x)<cal(m,y))
    			r=m;
    		else
    			l=m+1;
    	}
    	return l;
    }
    int main()
    {
    	int T,n;
    	scanf("%d",&T);
    	while(T--)
    	{
    		scanf("%d%d%d",&n,&l,&p);
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%s",zf[i]);
    			he[i]=strlen(zf[i])+he[i-1]+1;
    		}
    		dl[0]=SJd(1,n,0);
    		for(int i=1,he=0,ta=1;i<=n;i++)
    		{
    			while(he<ta&&i>dl[he].r)
    				he+=1;
    			int j=dl[he].z,zd=false;
    			dp[i]=cal(i,j);wz[i]=j;
    			while(he<ta&&efcz(max(dl[ta-1].l,i+1),dl[ta-1].r+1,i,dl[ta-1].z)<=dl[ta-1].r)
    				ta-=1,zd=true;
    			if(!zd)continue;
    			int l=efcz(max(dl[ta].l,i+1),dl[ta].r,i,dl[ta].z);
    			if(l>dl[ta].l)
    				dl[ta++].r=l-1;
    			dl[ta++]=SJd(l,n,i);
    		}
    		if(dp[n]>1e18)
    			printf("Too hard to arrange
    ");
    		else
    		{
    			printf("%.0Lf
    ",dp[n]);
    			int u=n,m=0;
    			while(u>0)
    			{
    				st[m++]=u;
    				u=wz[u];
    			}
    			for(int i=m-1,la=0;i>=0;i--)
    			{
    				for(int j=la+1;j<=st[i];j++)
    				{
    					printf("%s",zf[j]);
    					if(j<st[i])printf(" ");
    				}
    				la=st[i];
    				printf("
    ");
    			}
    		}
    		printf("--------------------");
    		if(T>0)printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Row Cache lock Problem
    AIX操作系统上安装Oracle数据库必不可少的几项检查工作
    如何使用MOS风格的代码背景?
    在Ubuntu 10上使用DLink DWA 130无线网卡
    PL/SQL Developer View SQL功能的一个Bug
    11g新特性SQL PLUS 错误日志
    生病了。。。
    ORA00600: [7005], [192]内部错误一例
    Linux:vmware下ubuntu更换网卡后无法识别网卡
    Linux:LFS:第一天:今天开始学习,计划7天时间
  • 原文地址:https://www.cnblogs.com/lnzwz/p/12444390.html
Copyright © 2020-2023  润新知