#2754. Count(count)

题目描述

`n+e`接收到了小叶子的信息,你的 $\text{hack}$ 失败了!
这条信息是这样的:
To `n+e`:
我的桌子忘记整理了,听说待会检查卫生,求帮忙。
叶子
小叶子的桌面上有 $n$ 本高度不相同的书,`n+e`现在需要把这些书按照一定的顺序摆放好。假设第 $i$ 本书的高度为 $h[i]$ ,`n+e`的摆放用一个 $1~n$ 的排列 $p_i$ 来表示。
定义一个摆放的混乱程度: $|h[p_2]-h[p_1]|+|h[p_3]-h[p_2]|+...+|h[p_n]-h[p_{n-1}]|$ ,即相邻两本书的高度差的绝对值之和。
已知合法的摆放要求其混乱程度不超过 $L$ 。
小叶子想要知道,`n+e`到底有多少种合法的摆放的方法呢?
作为将要参加 $\text{NOI}$ 的选手,你应该知道,小叶子只关心这个数对 $10^9+7$ 取模的结果。

题解

可以考虑从大到小放书,设 $f[i][0/1][0/1][k][s]$ 表示从大到小排序后的前 $i$ 本书,第 $1$ 个位置有没有放书,第 $n$ 个位置有没有放书,当前有 $k$ 个坑,当前侧边暴露出的周长和为 $s$ 的方案数。这里的坑指的是最左边的书和最右边的书中间的空缺部分,我们可以考虑先把这些坑看成一个单位的。

考虑插书的过程,如果 $k>0$ 的话:
1.我们可以补上某个坑,即转移到 $k-1$ ;
2.我们可以在某个坑的两侧插书,然后这些坑保留不变,即转移到 $k$ ;
3.我们可以在某个坑的中间插书,然后将这个坑分裂,变成两个一个单位的坑,即转移到 $k+1$ 。

如果第 $1/n$ 个位置没放书的话可以再按照上述分讨一下。

考虑到周长记不下状态,所以我们可以考虑将某次插入的书设成地平线,然后每次只要记录这个地平线上边的书侧面的周长即可。效率: $O(n^2L)$ 。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=105,M=1005,P=1e9+7;
int n,m,a[N],f[2][2][2][N][M],X,Y=1,s;
int main(){
    cin>>n>>m;
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);sort(a+1,a+n+1);
    if (n==1) return puts("1"),0;
    f[0][0][0][0][0]=f[0][1][0][0][0]=f[0][0][1][0][0]=1;
    for (int i=n-1;i;i--){
        memset(f[Y],0,sizeof f[Y]);
        for (int l=0;l<2;l++)
            for (int r=0;r<2;r++)
                for (int k=0;k<=n;k++)
                    for (int v,x,u=0;u<=m;u++){
                        v=u+(a[i+1]-a[i])*(k+k+(!l)+(!r));
                        if (v>m) break;x=f[X][l][r][k][u];
                        if (k){
                            (f[Y][l][r][k][v]+=1ll*x*(k+k)%P)%=P;
                            (f[Y][l][r][k-1][v]+=1ll*x*k%P)%=P;
                            (f[Y][l][r][k+1][v]+=1ll*x*k%P)%=P;
                        }
                        if (!l){
                            for (int j=0;j<2;j++)
                                (f[Y][j][r][k][v]+=x)%=P,
                                (f[Y][j][r][k+1][v]+=x)%=P;
                        }
                        if (!r){
                            for (int j=0;j<2;j++)
                                (f[Y][l][j][k][v]+=x)%=P,
                                (f[Y][l][j][k+1][v]+=x)%=P;
                        }
                    }
        X^=1;Y^=1;
                            
    }
    for (int i=0;i<=m;i++)
        (s+=f[X][1][1][0][i])%=P;
    cout<<s<<endl;return 0;
}

 

posted @ 2020-02-17 21:47  xjqxjq  阅读(163)  评论(0编辑  收藏  举报