当前位置:网站首页>【COCI 2020/2021 Round #2 D】Magneti(DP)
【COCI 2020/2021 Round #2 D】Magneti(DP)
2022-07-30 05:51:00 【SSL_TJH】
Magneti
题目链接:COCI 2020/2021 Round #2 D
题目大意
给你 n 个物品,每个有一个值,而且物品之间不同。
然后有一个长度为 L 的板子,然后你要把物品放在每个整点上面,使得两个物品之间的距离不小于它们权值的最大值。
然后问你有多少种方法。
思路
考虑 DP,发现不太能 DP,因为跟两个有关,但是不可以 2 n 2^n 2n。
考虑转化一下,发现如果我们确定了顺序,那最少要长度为多少的板子呢?
思考一下会发现两个之间占了 max ( a i , a i + 1 ) \max(a_i,a_{i+1}) max(ai,ai+1) 的空位,那总共要的位置就是这些的和加上 n n n。
那多出的位置我们可以用插板法来分配。
那问题就变成了求对于每个 max \max max 的和的结果,有多少种顺序对应呢?
考虑贡献的位置,也就是大的那个,于是考虑从小到大加数,那每次跟前面的多少个相邻就是贡献多少个自己。
然后考虑放进去之后会有若干块,块之间不相邻,之后再用数合并。
然后就列出一个 DP: f i , j , k , 0 / 1 / 2 , w f_{i,j,k,0/1/2,w} fi,j,k,0/1/2,w 为前 i i i 个数放进去,一边空着的 j j j 个块,两边空着的 k k k 个块,两段的块已经放了 0 / 1 / 2 0/1/2 0/1/2 个,当前 max \max max 的和为 w w w。
然后分类讨论转移。
发现会超时,因为是 O ( n 3 L ) O(n^3L) O(n3L) 的。
考虑优化,观察一下转移的式子会发现 j j j 只有在两端的时候才会加,所以 j j j 的大小其实也是 0 / 1 / 2 0/1/2 0/1/2,然后变成 O ( n 2 L ) O(n^2L) O(n2L) 就可以过了。
代码
#include<cstdio>
#include<algorithm>
#define mo 1000000007
using namespace std;
const int N = 51;
const int M = 1e4 + 10;
int n, L, a[N], jc[M], inv[M], invs[M];
int f[2][3][N][3][M], inv2;
int add(int x, int y) {
return x + y >= mo ? x + y - mo : x + y;}
int dec(int x, int y) {
return x < y ? x - y + mo : x - y;}
int mul(int x, int y) {
return 1ll * x * y % mo;}
int C(int x, int y) {
if (y < 0 || y > x) return 0; return mul(jc[x], mul(invs[y], invs[x - y]));}
int ksm(int x, int y) {
int re = 1; while (y) {
if (y & 1) re = mul(re, x); x = mul(x, x); y >>= 1;} return re;}
void Init() {
jc[0] = 1; for (int i = 1; i < M; i++) jc[i] = mul(jc[i - 1], i);
inv[0] = inv[1] = 1; for (int i = 2; i < M; i++) inv[i] = mul(inv[mo % i], mo - mo / i);
invs[0] = 1; for (int i = 1; i < M; i++) invs[i] = mul(invs[i - 1], inv[i]);
inv2 = ksm(2, mo - 2);
}
void ck(int &x, int y) {
x = add(x, y);
}
int main() {
// printf("%.3lf", (sizeof(f) * 2) / 1024.0 / 1024.0);
freopen("magnet.in", "r", stdin);
freopen("magnet.out", "w", stdout);
Init();
scanf("%d %d", &n, &L);
// for (int i = 1; i <= n; i++) a[i] = 1;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]); sort(a + 1, a + n + 1);
if (n == 1) {
printf("%d", L); return 0;
}
f[0][0][0][0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < 3; j++)
for (int k = 0; k + j < i; k++)
for (int l = 0; l <= 2; l++)
for (int s = 0; s <= L; s++)
if (f[(i & 1) ^ 1][j][k][l][s]) {
int x = f[(i & 1) ^ 1][j][k][l][s]; f[(i & 1) ^ 1][j][k][l][s] = 0;
if (l < 2) {
ck(f[i & 1][j + 1][k][l + 1][s], (2 - l) * x);
if (s + a[i] <= L) {
if (j) ck(f[i & 1][j - 1][k][l + 1][s + a[i]], mul(x, j));
if (k) ck(f[i & 1][j + 1][k - 1][l + 1][s + a[i]], mul(x, k * (2 - l)));
}
}
if (s + a[i] <= L) {
if (j) ck(f[i & 1][j][k][l][s + a[i]], mul(x, j));
if (k) ck(f[i & 1][j][k][l][s + a[i]], mul(x, 2 * k));
}
if (s + a[i] + a[i] <= L) {
if (j > 1) ck(f[i & 1][j - 2][k][l][s + a[i] + a[i]], x);
if (k > 1) ck(f[i & 1][j][k - 1][l][s + a[i] + a[i]], mul(x, mul(k, k - 1)));
if (j && k) ck(f[i & 1][j][k - 1][l][s + a[i] + a[i]], mul(x, mul(j, k)));
}
ck(f[i & 1][j][k + 1][l][s], x);
}
}
int ans = 0;
for (int i = 0; i <= L; i++) {
ck(ans, mul(f[n & 1][0][0][2][i], C(L - i + n - 1, n)));
}
printf("%d", ans);
return 0;
}
边栏推荐
- 一段神奇的没有主方法的代码
- uniapp中canvas与v-if更“配”
- Derivative Operations on Vectors and Derivative Operations on Vector Cross and Dot Products
- go : 使用gorm查询记录
- Go语学习笔记 - gorm使用 - 数据库配置、表新增 Web框架Gin(七)
- 理解和熟悉递归中的尝试
- 华为发布“十大发明”,包含计算、智能驾驶等新领域
- assert
- MySQL master-slave replication configuration construction, one step in place
- MySQL题外篇【ORM思想解析】
猜你喜欢
No, the Log4j vulnerability hasn't been fully fixed yet?
Graphical relational database design ideas, this is too vivid
阿里二面:Redis有几种集群方案?我答了4种
STL source code analysis: conceptual understanding of iterators, and code testing.
Equation Derivation Proof of Vector Triple Product
idea built-in translation plugin
相机坐标系,世界坐标系,像素坐标系三者转换,以及OPENGLDEFocal Length和Opengl 的 Fov转换
How does Redis prevent oversold and inventory deduction operations?
Proof of distance calculation from space vertex to plane and its source code
【雷达目标检测】恒定阈值法和恒虚警(CFAR)法及代码实现
随机推荐
ArrayList
@Bean 与 @Component 用在同一个类上,会怎样?
assert
Rodrigues: vector representation of rotation matrices
The terminal connection tools, rolling Xshell
go : go-redis 基础操作
Keil软件中map文件解析
Huawei released "ten inventions", including computing, intelligent driving and other new fields
Equation Derivation Proof of Vector Triple Product
MySQL什么时候用表锁,什么时候用行锁?
Process and Scheduled Task Management
The first artificial intelligence safety competition officially launched
【MySQL】MySQL中如何实现分页操作
Mobile phone side scroll to page to specify location
云服务器零基础部署网站(保姆级教程)
开发常用工具软件
When does MySQL use table locks and when does it use row locks?
schur completement
Go uses freecache for caching
go : go-redis set operations