2 条题解

  • 2
    @ 2022-9-13 16:45:42

    白日依山尽,黄河入海流。

    欲穷千里目,更上一层楼。

    大家好,这里是 myee,一个不会决策单调性的小萌新!


    设第 kk 句话长度为 lk1l_k-1,定义 Sk=i=1klkS_k=\sum_{i=1}^kl_k

    则显然把第 lrl\sim r 行写在一起的代价为 SrSl1L1P|S_r-S_{l-1}-L-1|^P。(考虑空格)

    注意到 SrSl1S_r-S_{l-1} 满足四边形恒等式与区间包含单调性,xL1P|x-L-1|^P 有凸性。

    因此 w(l,r)=SrSl1L1Pw(l,r)=|S_r-S_{l-1}-L-1|^P 满足四边形不等式,进而对 1D1D dp

    fr=min{fl1+w(l,r)1lr}f_r=\min\{f_{l-1}+w(l,r)|1\le l\le r\}

    决策单调性。而 fnf_n 正是我们所要求的。

    啥,为什么 xL1P|x-L-1|^P 有凸性?

    只用证 xP|x|^P 有凸性。

    由对称性,只用证 x0x\ge0xPx^P 有凸性。

    注意到这个东西二阶导在 x>0x>0 时总是非负。

    因此其(非严格)下凸得证。


    接下来就是考虑如何利用这个东西优化 dp 了。

    由于最小最优决策点单调不减,且函数单调增,考虑单调队列。

    维护每个决策点的对应最右目标,即其贡献区间。

    查询时如果队头元素到决策点最优目标了,记得出队。然后用队头元素更新当前解。

    更新完后,二分当前决策点的贡献区间,与当前队尾决策点相比较来一决胜负,从而更新队尾与当前决策点的贡献区间。

    如果队尾的贡献区间缩没了,将其出队。

    于是这题就做完辣!!!

    但是这个输出方案还是未免太困难了点吧。qwq


    下面是代码。

    注意坑点:

    • long double 来保证转移确定决策点时不 gg。
    // 由于带绝对值,所以凸性显然。
    // 因此可以决策单调性了。
    // 太逊了,并不会 SMAWK 算法,直接单调队列二分法了。
    
    // 是他是他就是他。
    // 决策单调性优化 dp。
    // 咕了很久。
    // 这个输出方案还是太离谱了。
    
    #include <algorithm>
    #include <deque>
    #include <stdio.h>
    #include <vector>
    typedef long long llt;
    typedef unsigned uint;typedef unsigned long long ullt;
    typedef bool bol;typedef char chr;typedef void voi;
    typedef double dbl;
    template<typename T>bol _max(T&a,T b){return(a<b)?a=b,true:false;}
    template<typename T>bol _min(T&a,T b){return(b<a)?a=b,true:false;}
    template<typename T>T lowbit(T n){return n&-n;}
    template<typename T>T gcd(T a,T b){return b?gcd(b,a%b):a;}
    template<typename T>T lcm(T a,T b){return(a!=0||b!=0)?a/gcd(a,b)*b:(T)0;}
    template<typename T>T exgcd(T a,T b,T&x,T&y){if(b!=0){T ans=exgcd(b,a%b,y,x);y-=a/b*x;return ans;}else return y=0,x=1,a;}
    template<typename T>T power(T base,T index,T mod)
    {
        T ans=1%mod;
        while(index)
        {
            if(index&1)ans=ans*base%mod;
            base=base*base%mod,index>>=1;
        }
        return ans;
    }
    typedef long double ldbl;
    const ldbl inf=1e18+.000000000000000005;
    ldbl Pow(ldbl base,uint index)
    {
        ldbl ans=1;
        while(index)
        {
            if(index&1)ans=ans*base;
            base=base*base,index>>=1;
        }
        return ans;
    }
    uint Right[100005],Left[100005];
    chr C[100005][35];
    uint Len[100005],S[100005];
    ldbl Ans[100005];
    int main()
    {
    #ifdef MYEE
        freopen("QAQ.in","r",stdin);
    #endif
        uint t;scanf("%u",&t);
        while(t--)
        {
            uint n,L,p;scanf("%u%u%u",&n,&L,&p);
            for(uint i=1;i<=n;i++)
            {
                scanf("%s",C[i]);Len[i]=1;while(C[i][Len[i]-1])Len[i]++;
                S[i]=S[i-1]+Len[i];
            }
            auto w=[&](uint l,uint r){return S[r]-S[l]>L+1?Pow((S[r]-S[l])-(L+1),p):Pow((L+1)-(S[r]-S[l]),p);};
            Right[0]=n;
            std::deque<uint>D{0};
            for(uint i=1;i<=n;i++)
            {
                while(Right[D.front()]<i)D.pop_front();
                Left[i]=D.front();Ans[i]=Ans[D.front()]+w(D.front(),i);
                if(Ans[i]>inf)continue;
                while(true)
                {
                    uint p=D.back();
                    uint l=i,r=n;
                    while(l<r)
                    {
                        uint mid=(l+r+1)>>1;
                        if(Ans[p]+w(p,mid)<=Ans[i]+w(i,mid))l=mid;
                        else r=mid-1;
                    }
                    Right[p]=l;
                    if(D.size()>1&&Right[D[D.size()-2]]>=l)D.pop_back();
                    else break;
                }
                Right[i]=n;D.push_back(i);
            }
            if(Ans[n]>inf)puts("Too hard to arrange");
            else{
                printf("%lld\n",(llt)Ans[n]);
                std::vector<uint>P;
                uint p=n;while(p)P.push_back(p),p=Left[p];
                std::reverse(P.begin(),P.end());
                for(auto v:P)while(p<v)p++,printf("%s%c",C[p]," \n"[p==v]);
            }
            puts("--------------------");
        }
        return 0;
    }
    
    • 0
      @ 2022-8-29 9:45:16
      #include<cstdio>
      #include<cmath>
      #include<cstring>
      #define RG register
      #define R RG int
      #define G c=getchar()
      #define Calc(i,j) f[j]+qpow(abs(s[i]-s[j]-L))//计算函数值
      using namespace std;
      typedef long double LD;//开long double
      const int N=1e5+9;
      int n,L,P,s[N],q[N],k[N],pr[N];
      LD f[N];
      char str[N][33];
      inline int in(){
          RG char G;
          while(c<'-')G;
          R x=c&15;G;
          while(c>'-')x*=10,x+=c&15,G;
          return x;
      }
      inline LD qpow(RG LD b){//自己写快速幂
          RG LD a=1;
          for(R k=P;k;k>>=1,b*=b)
              if(k&1)a*=b;
          return a;
      }
      inline int bound(R x,R y){//二分临界值
          R l=x,r=n+1,m;//左端点设为x减小常数
          while(l<r){
              m=(l+r)>>1;
              Calc(m,x)>=Calc(m,y)?r=m:l=m+1;
          }
          return l;
      }
      int main(){
          R T=in(),i,h,t;
          while(T--){
              n=in();L=in()+1;P=in();//把L处理了一下
              for(i=1;i<=n;++i){
                  if(scanf("%s",str[i]));
                  s[i]=s[i-1]+strlen(str[i])+1;//记前缀和
              }
              for(q[i=h=t=1]=0;i<=n;++i){
                  while(h<t&&k[h]<=i)++h;
                  f[i]=Calc(i,q[h]);pr[i]=q[h];//记录转移位置方便输出方案
                  while(h<t&&k[t-1]>=bound(q[t],i))--t;
                  k[t]=bound(q[t],i);q[++t]=i;
              }
              if(f[n]>1e18)puts("Too hard to arrange");
              else{
                  printf("%.0Lf\n",f[n]);
                  for(q[t=0]=i=n;i;q[++t]=i=pr[i]);
                  for(;t;--t){
                      for(i=q[t]+1;i<q[t-1];++i)
                          printf("%s ",str[i]);
                      puts(str[i]);//行末不要搞空格
                  }
              }
              puts("--------------------");
          }
          return 0;
      }
      
      • 1

      信息

      ID
      1563
      时间
      2000ms
      内存
      256MiB
      难度
      6
      标签
      (无)
      递交数
      58
      已通过
      17
      上传者