zoukankan      html  css  js  c++  java
  • sss

    <更新提示>


    <正文>

    四边形不等式

    定义:设(w(x,y))是定义在整数集合上的的二元函数,若对于定义域上的任意整数(a,b,c,d),在满足(aleq bleq c leq d)时,都有(w(a,d)+w(b,c)geq w(a,c)+w(b,d))成立,则称函数(w)满足四边形不等式。

    定理1:四边形不等式的等价表达

    (w(x,y))是定义在整数集合上的的二元函数,若对于定义域上的任意整数(a,b),在满足(a< b)时,都有(w(a,b+1)+w(a+1,b)geq w(a,b)+w(a+1,b+1))成立,则称函数(w)满足四边形不等式。

    证明:

    (a<c),则有(w(a,c+1)+w(a+1,c)geq w(a,c)+w(a+1,c+1))

    (a+1<c),则有(w(a+1,c+1)+w(a+2,c)geq w(a+1,c)+w(a+2,c+1))

    两式相加,消去相同项可得:(w(a,c+1)+w(a+2,c)geq w(a,c)+w(a+2,c+1))

    类似的,只要(a+k<c)就可以得到:(w(a,c+1)+w(a+k,c)geq w(a,c)+w(a+k,c+1))

    所以对于(aleq bleq c),就有(w(a,c+1)+w(b,c)geq w(a,c)+w(b,c+1))

    同理可证对于(aleq bleq cleq d),有(w(a,d)+w(b,c)geq w(a,c)+w(b,d))

    定理2:决策单调性

    定义:对于形如(f[i]=min_{0leq j <i}{f[j]+val(j,i)})的状态转移方程,记(p[i])(f[i])的最优决策。若(p)([1,n])上单调不减,则称(f)具有决策单调性。

    在状态转移方程(f[i]=min_{0leq j <i}{f[j]+val(j,i)})中,若函数(val)满足四边形不等式,则(f)具有决策单调性。

    证明:
    对于(forall iin[1,n],forall jin[0,p[i]-1]),由(p[i])的最优性可得:$$f[p[i]]+val(p[i],i)leq f[j]+val(j,i) ag1$$
    设有(i'in[i+1,n]),因为(val)满足四边形不等式,所以$$val(j,i')+val(p[i],i)geq val(j,i)+val(p[i],i')$$
    整理可得:

    [val(p[i],i')-val(p[i],i)leq val(j,i')-val(j,i) ag2 ]

    ((1)(2))两式相加,可得:

    [f[p[i]]+val(p[i],i')leq f[j]+val(j,i') ]

    所以,对于(i)以后的任意一个(i')(p[i])都是比任意(j<p[i])更优的决策,故(f)具有决策单调性。

    诗人小G

    Description

    小G是一个出色的诗人,经常作诗自娱自乐。但是,他一直被一件事情所困扰,那就是诗的排版问题。

    一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在一行中, 注意一行中可以放的句子数目是没有限制的。小G给每首诗定义了一个行标准长度(行的长度为一行中符号的总个数),他希望排版后每行的长度都和行标准长度相差不远。显然排版时,不应改变原有的句子顺序,并且小G不允许把一个句子分在两行或者更多的行内。在满足上面两个条件的情况下,小G对于排版中的每行定义了一个不协调度, 为这行的实际长度与行标准长度差值绝对值的P次方,而一个排版的不协调度为所有行不协调度的总和。

    小G最近又作了几首诗,现在请你对这首诗进行排版,使得排版后的诗尽量协调(即不协调度尽量小),并把排版的结果告诉他。

    Input Format

    输入包含多组数据。

    第一行包含一个整数T,表示诗的数量,接下来是T首诗,这里一首诗即为一组数据。每组数据的第一行包含三个由空格分隔的正整数N、L、P,其中N表示这首诗句子的数目,L表示这首诗的行标准长度,P的含义见问题描述。从第2行开始,每行为一个句子,句子由英文字母、数字、标点符号等符号组成(ASCII码33~127, 但不包含 ‘-’)。

    Output Format

    对于每组数据,若最小的不协调度不超过10181018,则一行一个数表示不协调度,若最小的不协调度超过10181018,则输出"Too hard to arrange"(不包含引号)。每组数据结束后输出"--------------------"(不包括引号),共20个"-","-"的ASCII码为45,请勿输出多余的空行或者空格。

    Sample Input

    4
    4 9 3
    brysj,
    hhrhl.
    yqqlm,
    gsycl.
    4 9 2
    brysj,
    hhrhl.
    yqqlm,
    gsycl.
    1 1005 6
    poet
    1 1004 6
    poet
    

    Sample Output

    108
    --------------------
    32
    --------------------
    Too hard to arrange
    --------------------
    1000000000000000000
    --------------------
    

    解析

    (f[i])代表对前(i)句诗版排的最小不协调度,(a[i])为第(i)句诗的长度,(sum[i])(a[i])的前缀和。

    [f[i]=min_{0leq j<i}{f[j]+|sum[i]-sum[j]+i-j-1-L|^P} ]

    其中,设(val(j,i)=|sum[i]-sum[j]+i-j-1-L|^P),那么方程符合上述四边形不等式中提到的状态转移方程的格式。

    我们可以证明函数(val(j,i))满足四边形不等式,进而得知(f)具有决策单调性,也可以打标发现(f)具有决策单调性。现在,我们讨论如何利用决策单调性对动态规划进行优化。

    我们首先考虑维护决策数组(p),首先它一定是单调不减的。对于求出一个新的状态(f[i])后,我们要考虑(i)可以作为哪些状态的最优决策。由决策单调性可知,数组(p)中一定存在一个最小位置(pos),使得([pos,n])中的所有决策都劣于(i),我们需要将(p)数组中下标在([pos,n])的值都改为(i)

    在数组上大量修改时很费时的,我们不妨用一个队列来代替(p)数组,在队列中存储若干个三元组((j,l,r)),代表(p)数组中([l,r])位置的值都为(j),这样我们就可以高效地维护队列了。

    对于一个新的状态(f[i]),我们先将队头已经过时的决策弹出,然后取队头决策就可以进行转移。

    如何加入一个决策(i)呢?我们可以将决策(i)与队尾的决策逐个比较,如果(i)优于队尾的某个整段决策,就将整段决策弹出队列,直到队列为空。或者,遇到某一段决策,(i)不比整段决策优,那就在这段决策中进行二分查找,找到最小的(pos)即可。

    最后,我们加入决策(i),有效范围为([pos,n])。当然,如果(pos)处于原本的一段中间,则还需修改原本队尾决策的右端点。

    (Code:)

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5+20;
    const long long INF = 1e18;
    struct state{int j,l,r;}q[N]; 
    int n,L,p,a[N];
    long double f[N],sum[N];
    char poem[40];
    inline void input(void)
    {
    	scanf("%d%d%d",&n,&L,&p);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%s",poem);
    		a[i] = strlen(poem);
    		sum[i] = sum[i-1] + a[i];
    	}
    } 
    inline long double power(long double val)
    {
    	if ( val < 0 ) val = -val; 
    	long double res = 1;
    	int p_ = p;
    	while ( p_ )
    	{
    		if ( 1 & p_ ) res *= val;
    		p_ >>= 1 , val *= val;
    	}
    	return res;
    }
    inline long double calc(int i,int j)
    {
    	return f[j] + power( sum[i] - sum[j] + i - j - 1 - L );
    }
    inline int binary_search(state T,int i)
    {
    	int l = T.l , r = T.r;
    	while ( l + 1 < r )
    	{
    		int mid = (l+r) >> 1;
    		if ( calc( mid , T.j ) < calc( mid , i ) )
    			l = mid;
    		else r = mid;
    	}
    	if ( calc( l , T.j ) >= calc( l , i ) ) return l;
    	if ( calc( r , T.j ) >= calc( r , i ) ) return r;
    	return r+1;
    }
    inline void dp(void)
    {
    	int head = 1 , tail = 0 , pos;
    	f[0] = 0 , q[++tail] = (state){0,1,n};
    	for (int i=1;i<=n;i++)
    	{
    		while ( head <= tail && q[head].r < i ) head++;
    		f[i] = calc( i , q[head].j );
    		if ( head > tail || calc(n,i) <= calc(n,q[tail].j) )
    		{
    			while ( head <= tail && calc(q[tail].l,i) <= calc(q[tail].l,q[tail].j) ) tail--;
    			if ( head > tail )
    				q[++tail] = (state){i,i+1,n};
    			else
    			{
    				int pos = binary_search(q[tail],i);
    				q[tail].r = pos-1;
    				q[++tail] = (state){i,pos,n}; 
    			}
    		}
    	}
    }
    int main(void)
    {
    	int T;
    	scanf("%d",&T);
    	while (T--)
    	{
    		input();
    		dp();
    		if ( f[n] > INF ) puts("Too hard to arrange");
    		else printf("%lld
    ",(long long)f[n]);
    		puts("--------------------");
    	}
    	return 0;
    }
    

    <后记>

  • 相关阅读:
    数据结构(二)之链表
    数据结构(一)之数组,栈,队列
    记第一次学习Mybatis
    多线程基本实现方法(一)
    TCP三次握手及四次四次释放协议解析
    《绝不划水队》第一次作业:项目选题
    第一次博客作业
    vim cheatsheet
    js cheatsheet
    js re cheatsheet
  • 原文地址:https://www.cnblogs.com/Parsnip/p/11133134.html
Copyright © 2011-2022 走看看