传送门:bzoj2817


题解

考虑拆去绝对值符号,而数列的相对大小波动如下:
【BZOJ】2817: [ZJOI2012]波浪-DP
发现只有转折点的数有贡献,可以套用两个套路:

  • 从小到大插入去掉绝对值的影响
  • DPDP只需要记录拆分成了几段(相对位置)

f[i][j][k]f[i][j][k]表示依次插入了1i1-i,分成了jj段,差值之和为kk的方案数:

插入i+1i+1时有以下情况:

  • 左右两边都有数,f[i][j][k]×(j1)f[i+1][j1][k+2(i+1)]f[i][j][k]\times (j-1)\to f[i+1][j-1][k+2(i+1)]
  • 只有一侧有数,f[i][j][k]×2jf[i+1][j][k]f[i][j][k]\times 2j\to f[i+1][j][k]
  • 两侧都没有数,f[i][j][k]×(j+1)f[i+1][j+1][k2(i+1)]f[i][j][k]\times (j+1)\to f[i+1][j+1][k-2(i+1)]

段覆盖左右端点时情况比较特殊,所以还需要加一维,f[i][j][k][l]f[i][j][k][l]表示左右端点有l(0l2)l(0\leq l\leq 2)个被占用了的方案数。

卡精度+卡内存
分情况用__float128/double


代码

做了许久口胡选手,代码能力急剧下降

#include<bits/stdc++.h>
using namespace std;
const int N=102,S=4500;
int n,m,K;
double f[2][N][S*2+5][3];
__float128 g[2][N][S*2+5][3];

template<class T>
inline void prit(T x)
{
    int nw=x;printf("%d.",nw);
    for(;K;--K){
        x=(x-nw)*10.0;
        if(K==1) x+=0.5;
        nw=x;printf("%d",nw);
    }
}

int main(){
    int i,j,k,t,pr=0;
    scanf("%d%d%d",&n,&m,&K);
    if(K>8){
        __float128 v,ans=0;g[0][0][S][0]=1;
        for(i=1;i<=n;++i){
            pr^=1;memset(g[pr],0,sizeof(g[pr]));
            for(j=0;j<=i;++j)
             for(k=0;k<=(S<<1);++k)
              for(t=0;t<=2;++t) if((v=g[pr^1][j][k][t])!=0){
                  if(t<2){
                      if(j) g[pr][j][k+i][t+1]+=v*(2-t);
                      g[pr][j+1][k-i][t+1]+=v*(2-t);
                  }
                  if(j>1) g[pr][j-1][k+(i<<1)][t]+=v*(j-1);
                  g[pr][j+1][k-(i<<1)][t]+=v*(j+1-t);
                  g[pr][j][k][t]+=v*((j<<1)-t);
              }
        }
         for(k=S+m;k<=(S<<1);++k)
          ans+=g[pr][1][k][2];
        for(i=2;i<=n;++i) ans/=i*1.0;
		prit(ans);
    }else{
        double v,ans=0;f[0][0][S][0]=1;
        for(i=1;i<=n;++i){
            pr^=1;memset(f[pr],0,sizeof(f[pr]));
            for(j=0;j<=i;++j)
             for(k=0;k<=(S<<1);++k)
              for(t=0;t<=2;++t) if((v=f[pr^1][j][k][t])!=0){
                  if(t<2){
                      if(j) f[pr][j][k+i][t+1]+=v*(2-t);
                      f[pr][j+1][k-i][t+1]+=v*(2-t);
                  }
                  if(j>1) f[pr][j-1][k+(i<<1)][t]+=v*(j-1);
                  f[pr][j+1][k-(i<<1)][t]+=v*(j+1-t);
                  if(j) f[pr][j][k][t]+=v*((j<<1)-t);
              }
        }
         for(k=S+m;k<=(S<<1);++k)
          ans+=f[pr][1][k][2];
		for(i=2;i<=n;++i) ans/=i*1.0;
		  prit(ans);
    }
    return 0;
}

相关文章: