题目大意

将 \(N\) 个互不相同的整数 \(A_1 , A_2 , ⋯ , A_N\) 任意排列成 \(B_1 , B_2 , ⋯ , B_N\) 。

要求 \(∑^{N−1}_{i=1} |B_{i+1} − B_i | ≤ L\)

计数方案数 \(N ≤ 100\ L ≤ 1000\)。

解题思路

是一个比较经典的 DP 方式。但是大家都不屑于讲清楚这个转移,所以只好从网上找一篇记录一下。

首先考虑将贡献差分一下,假设在 \(a_i\) 放下去前一刻有 \(i\) 个空位,则进行放置这个操作的贡献就是 \((a_i-a_{i-1})\times i\)。

那么考虑从小到大放置,每一时刻就会是一些连续段。

设 \(f[i][j][s][d]\) 表示已经放置前 \(i\) 个数,分成 \(j\) 段,目前贡献为 \(s\),有 \(d\) 个边界已确定的方案数。

注意这个 DP 中我们只需要保证每段是否在边界以及相邻两段之间有空位即可,不关心每段的实际位置。

从转移来感受一下上面这句话:

  1. 新建一段 (这一段可以放在边界除外的任意 \(j+1\) 个空隙内);
  2. 合并两段;
  3. 放在其中一段的其中一端;
  4. 新建一段并钦定其为边界;
  5. 接在最左段 (不能为边界) 的左端并钦定为边界,或接在最右段 (不能为边界) 的最右端并钦定为边界;

转移的时候注意判合法。

#include <set>
#include <map>
#include <queue>
#include <bitset>
#include <vector>
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std; const int N(105), M(1005), mod(1e9 + 7); int n, L, a[N];
int b[N];
int f[N][N][M][3]; inline void read(int &x){
x = 0; int f = 1, c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)) x = x * 10 + c - 48, c = getchar();
x *= f;
} inline void MOD(int &x){ x = x + ((x >> 31) & mod); } int main(){
read(n), read(L);
for(int i(1); i <= n; ++i) read(a[i]);
if(n == 1) return puts("1"), 0;
sort(a + 1, a + n + 1);
for(int i(2); i <= n; ++i) b[i] = a[i] - a[i - 1];
f[0][0][0][0] = 1;
for(int i(0); i < n; ++i)
for(int j(0); j <= i; ++j)
for(int s(0); s <= L; ++s)
for(int d(0); d <= 2; ++d){
if(!f[i][j][s][d]) continue;
int more = b[i + 1] * (j * 2 - d); if(s + more > L) continue;
MOD(f[i + 1][j + 1][s + more][d] += 1LL * f[i][j][s][d] * (j + 1 - d) % mod - mod);
if(j) MOD(f[i + 1][j - 1][s + more][d] += 1LL * f[i][j][s][d] * (j - 1) % mod - mod);
MOD(f[i + 1][j][s + more][d] += 1LL * f[i][j][s][d] * (2 * j - d) % mod - mod);
if(d == 2) continue;
MOD(f[i + 1][j + 1][s + more][d + 1] += 1LL * f[i][j][s][d] * (2 - d) % mod - mod);
if(j) MOD(f[i + 1][j][s + more][d + 1] += 1LL * f[i][j][s][d] * (2 - d) % mod - mod);
}
int ans = 0;
for(int i(0); i <= L; ++i) MOD(ans += f[n][1][i][2] - mod);
printf("%d\n", ans);
return 0;
}
/* Hemerocallis */

[题解] [LOJ2743]「JOI Open 2016」摩天大楼的更多相关文章

  1. [LOJ#2743][DP]「JOI Open 2016」摩天大楼

    题目传送门 DP 经典题 考虑从小到大把数加入排列内 如下图(\(A\) 已经经过排序): 我们考虑如上,在 \(i\) ( \(A_i\) )不断增大的过程中,维护上面直线 \(y=A_i\) 之下 ...

  2. 【题解】LOJ2759. 「JOI 2014 Final」飞天鼠(最短路)

    [题解]LOJ2759. 「JOI 2014 Final」飞天鼠(最短路) 考虑最终答案的构成,一定是由很多飞行+一些上升+一些下降构成. 由于在任何一个点上升或者下降代价是一样的,所以: 对于上升操 ...

  3. 「JOI 2017 Final」JOIOI 王国

    「JOI 2017 Final」JOIOI 王国 题目描述 题目译自 JOI 2017 Final T3「 JOIOI 王国 / The Kingdom of JOIOI」 JOIOI 王国是一个 H ...

  4. 「JOI 2015 Final」分蛋糕 2

    「JOI 2015 Final」分蛋糕 2 题解 这道题让我想起了新年趣事之红包这道DP题,这道题和那道题推出来之后的做法是一样的. 我们可以定义dp[i][len][1] 表示从第i块逆时针数len ...

  5. LOJ#2351. 「JOI 2018 Final」毒蛇越狱

    LOJ#2351. 「JOI 2018 Final」毒蛇越狱 https://loj.ac/problem/2351 分析: 首先有\(2^{|?|}\)的暴力非常好做. 观察到\(min(|1|,| ...

  6. 【LOJ】#3014. 「JOI 2019 Final」独特的城市(长链剖分)

    LOJ#3014. 「JOI 2019 Final」独特的城市(长链剖分) 显然我们画一条直径,容易发现被统计的只可能是直径某个距离较远的端点到这个点的路径上的值 用一个栈统计可以被统计的点,然后我们 ...

  7. 「JOI 2014 Final」飞天鼠

    「JOI 2014 Final」飞天鼠 显然向上爬是没有必要的,除非会下降到地面以下,才提高到刚好为0. 到达一个点有两种情况:到达高度为0和不为0. 对于高度不为0的情况,显然花费的时间越少高度越高 ...

  8. 「JOI 2015 Final」城墙

    「JOI 2015 Final」城墙 复杂度默认\(m=n\) 暴力 对于点\((i,j)\),记录\(ld[i][j]=min(向下延伸的长度,向右延伸的长度)\),\(rd[i][j]=min(向 ...

  9. 「JOI 2015 Final」舞会

    「JOI 2015 Final」舞会 略微思考一下即可知该过程可以化为一棵树.(3个贵族中选择1个,即新建一个节点连向这3个贵族). 该树的结点个数为\(2n\). 考虑二分答案mid. 判定的是公主 ...

随机推荐

  1. Pipeline 有什么好处,为什么要用 pipeline?

    答:可以将多次 IO 往返的时间缩减为一次,前提是 pipeline 执行的指令之间没有 因果相关性.使用 redis-benchmark 进行压测的时候可以发现影响 redis 的 QPS 峰值的一 ...

  2. phpstorm chrome 添加xdebug扩展

    转:https://blog.csdn.net/ltcm_sakura/article/details/102967859 一.Xdebug helper:php调试插件 http://chromec ...

  3. 实验配置cisco单臂路由

    第一步 搭建实验拓扑图 第二步 对路由器做基本配置 为路由器创建名称: 设置进入特权模式 口令:控制台登录密码:vty登录密码 禁用DNS查找: 加密明文密码: 创建一个向访问设备者发出警告的标语&q ...

  4. Netty学习摘记 —— 深入了解Netty核心组件

    本文参考 本篇文章是对<Netty In Action>一书第三章"Netty的组件和设计"的学习摘记,主要内容为Channel.EventLoop.ChannelFu ...

  5. 规范之“用流中的Stream.Of(arr1,arr2)将两个集合合并”

    案例:用流中的Stream.Of(arr1,arr2)将两个集合合并 /** * 功能描述: * 两个对象集合添加到一起 * 在用flatMap扁平化改为Stream<User> * 这样 ...

  6. 编译器如何处理C++不同类中同名函数(参数类型个数都相同)

    转载请注明出处,版权归作者所有 lyzaily@126.com yanzhong.lee 作者按: 从这篇文章中,我们主要会认识到一下几点: 一.不类中的特征标相同的同名函数,它们是不同的函数,原因就 ...

  7. C语言小游戏——2048

      2048   2048这款游戏的玩法很简单,每次可以选择上下左右滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢.相撞时会相加. ...

  8. C++ 虚继承实现原理(虚基类表指针与虚基类表)

    虚继承和虚函数是完全无相关的两个概念. 虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝.这将存在两个问题:其一,浪费存储空间:第二,存在二义性问题,通常可 ...

  9. css中几个重要概念

    替换元素与非替换元素 替换元素:是指浏览器根据元素的标签和属性来决定元素的具体内容. 例如"<img src="xx.jpg">浏览器会根据标签的src属性的 ...

  10. jboss7学习2-jboss7入门(端口和访问的ip问题)

    1.下载地址: http://www.jboss.org/jbossas/downloads ,下载Certified Java EE 6 Full Profile版本. 2.解压 jboss-as- ...