• P1912 [NOI2009]诗人小G[决策单调性优化]


    地址

    n个数划分若干段,给定$L$,$p$,每段代价为$|sum_i-sum_j-1-L|^p$,求总代价最小。


    正常的dp决策单调性优化题目。不知道为什么luogu给了个黑题难度。$f[i]$表示最小代价。然后有个正常的dp方程。

    $f[i]=min { f[j]+|sum_i-sum_j-1-L|^p } $

    然后观察发现带高次项,不好斜率优化或单调队列,考虑有没有决策单调性。本来是可以打表证明的,然后拍一下。然而我杠一波瞎证了一下单调性。

    $证明:$

    $已知f[j]+|sum_i-sum_j-1-L|^p < f[j']+|sum_i-sum_{j'}-1-L|^p$

    $要证f[j]+|sum_i-sum_j-L|^p < f[j']+|sum_i-sum_{j'}-L|^p     (j'<j)(就是i加了1)$

    $即证|sum_i-sum_{j'}-1-L|^p+|sum_i-sum_j-L|^p < |sum_i-sum_j-1-L|^p+|sum_i-sum_{j'}-L|^p$

    $即|sum_i-sum_{j'}-1-L|^p-|sum_i-sum_{j'}-L|^p < |sum_i-sum_j-1-L|^p-|sum_i-sum_j-L|^p$

    $然后把其看成关于j的函数,或者就把S_i-S_j-L看成x简便一些,j增大,S_j增大,x总的减小。下面看单调性。可能证的不太严谨,有问题还望指教。$

    $f(x)=|x-1|^p-|x|^p  (p为大于2正整数)$

    $①p为偶数,则f(x)=(x-1)^p-x^p$

    $f'(x)=p(x-1)^{p-1}-px^{p-1}$

    $x>=1时显然小于0,此段单调减$

    $0<=x<1时p(x-1)^{p-1}<px^{p-1}即p(x-1)^{p-1}-px^{p-1}<0,此段单调减$

    $x<0时也有上述关系。$

    $又因为x∈R内函数值是连续(就是几个转折点值在左右边两个范围内算出来的f都一样的)的,所以整个是一直单调减的。$

    $②p为奇数,p-1为偶,则$

    $x>=1时f'(x)=p(x-1)^{p-1}-px^{p-1}<0单调减$

    $0<=x<1时f(x)=(1-x)^p-x^p,则f'(x)=-p(x-1)^{p-1}-px^{p-1}<0因为偶数次方必定大于0嘛$

    $x<0$时$f(x)=(1-x)^p+x^p,f'(x)=-p(x-1)^{p-1}+px^{p-1}$

    $∵x-1<x<0$

    $∴(x-1)^{p-1}>x^{p-1}$

    $∴f'(x)=-p(x-1)^{p-1}+px^{p-1}<0$

    $综上,p为奇或偶都有导数小于0,f随x单调减,j增大,S_j增大,x减小,f必然增大,则原不等式得证。$

    $所以满足决策单调性。$

    $证毕。$

    好像有漏洞?算了不管了。

    然后随便写写模板就行啦。

    注意一下要用long double精度/范围大,不然long long会爆。注意反而不要考虑会不会爆,考虑你就错了。具体见calc函数。


    错误×1:怕calc爆掉,加了特判,忽视了因此会导致的队列弹出时会提前结束。

    中二气息的结构体不用管。。

     1 #include<bits/stdc++.h>
     2 #define dbg(x) cerr<<#x<<"="<<x<<endl
     3 using namespace std;
     4 typedef long double ll;
     5 typedef double db;
     6 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;}
     7 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;}
     8 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
     9 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    10 template<typename T>inline T read(T&x){
    11     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    12     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    13 }
    14 inline ll fpow(ll x,int p){ll ret=1;for(;p;p>>=1,x=x*x)if(p&1)ret=ret*x;return ret;}//快速幂都不会写了。。 
    15 inline int Abs(int x){return x>0?x:-x;}
    16 const int N=100000+7;ll INF=1e18;
    17 struct izayoi_sakuya{
    18     int l,r,pos;
    19     izayoi_sakuya(int l0=0,int r0=0,int pos0=0):l(l0),r(r0),pos(pos0){}
    20 }q[N];
    21 char s[N][32];
    22 ll f[N],lim;
    23 int sum[N],pre[N];
    24 int T,L,p,n,l,r;
    25 inline ll calc(int j,int i){return f[j]+fpow(Abs(sum[i]-sum[j]-1-L),p);}
    26 /*这是原来的
    27 inline ll calc(int j,int i){
    28     ll x=Abs(sum[i]-sum[j]-1-L);
    29     if(x>lim)return INF+1;
    30     ll po=fpow(x,p);
    31     if(f[j]>(ll)1e18-po)return INF+1;
    32     return f[j]+po;
    33 }
    34 */
    35 inline int find_pos(int L,int R,int j,int i){
    36     int mid;
    37     while(L<R){
    38         mid=L+R>>1;
    39         if(calc(j,mid)>=calc(i,mid))R=mid;
    40         else L=mid+1;
    41     }
    42     return R;
    43 }
    44 inline void dp(){
    45     q[l=r=1]=izayoi_sakuya(1,n,0);
    46     for(register int i=1;i<=n;++i){
    47         f[i]=calc(q[l].pos,i);pre[i]=q[l].pos;//dbg(i),dbg(f[i]),dbg(sum[i]);
    48         if(i==q[l].r)++l;else ++q[l].l;
    49         if(f[i]>INF)continue; 
    50         while(l<=r&&calc(q[r].pos,q[r].l)>=calc(i,q[r].l))--r;
    51         if(r<l)q[r=l]=izayoi_sakuya(i+1,n,i);
    52         else{
    53             int k;if(calc(q[r].pos,q[r].r)<=calc(i,q[r].r))k=q[r].r+1;
    54             else k=find_pos(q[r].l,q[r].r,q[r].pos,i);//dbg(i),dbg(k);
    55             if(k<=n)q[r].r=k-1,q[++r]=izayoi_sakuya(k,n,i);
    56         }
    57     }
    58 }
    59 inline void print(int x,int y){
    60     if(x)print(pre[x],x);
    61     for(register int i=x+1;i<=y;++i)printf("%s",s[i]),i==y?putchar('
    '):putchar(' ');
    62 }
    63 
    64 int main(){//freopen("test.in","r",stdin);freopen("tmp.out","w",stdout);
    65     read(T);while(T--){
    66         read(n),read(L),read(p);lim=(ll)ceil(pow(1e18,1.0/(db)p));
    67         for(register int i=1;i<=n;++i)scanf("%s",s[i]),sum[i]=sum[i-1]+strlen(s[i])+1;
    68         dp();if(f[n]>INF)printf("Too hard to arrange
    ");
    69         else printf("%lld
    ",(long long)f[n]),print(pre[n],n);
    70         printf("--------------------
    ");
    71     }
    72     return 0;
    73 }
  • 相关阅读:
    JavaScript学习总结【5】、JS DOM
    JavaScript学习总结【11】、JS 运动
    JavaScript学习总结【7】、JS RegExp
    JavaScript学习总结【1】、初识JS
    JavaScript学习总结【10】、DOM 事件
    直接选择排序及交换二个数据的实现
    快速排序
    Lucene.net搜索结果排序(单条件和多条件)
    冒泡排序
    直接插入排序的三种实现
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10479132.html
Copyright © 2020-2023  润新知