当前位置:网站首页>Boss Rush (二分答案 + 状压DP)
Boss Rush (二分答案 + 状压DP)
2022-07-30 04:09:00 【小酒窝.】
Boss Rush
题意
给定 n 个技能,每个技能只能用一次。
每个技能有冷却时间 t i t_i ti,如果一个技能在时间 x 释放,那么直到 x + t i − 1 x+t_i-1 x+ti−1 时间内就不能再释放其他技能。
每个技能有伤害持续时间 l e n i len_i leni,如果技能在时间 x 释放,那么将会在第 x + j ( 0 ≤ j < l e n i ) x+j\ (0\leq j < len_i) x+j (0≤j<leni) 时刻产生 d i , j d_{i,j} di,j 伤害。
问,将生命值为 H 的 boss 击败最少需要用多少时间?
1 ≤ n ≤ 18 , 1 ≤ H ≤ 1 0 18 , 1 \leq n \leq 18, 1\leq H\leq 10^{18}, 1≤n≤18,1≤H≤1018,
1 ≤ t i , l e n i ≤ 100 000 , 1 ≤ d i , j ≤ 1 0 9 1 \leq t_i,len_i\leq 100\,000,\ 1\leq d_{i,j}\leq 10^9 1≤ti,leni≤100000, 1≤di,j≤109
思路
n 很小,考虑状压DP,求打出的最大伤害。
但是时间并不固定,无法使得时间花费最少,所以考虑二分答案将时间固定,然后在这个时间范围内状压DP,看打出的最大伤害是否大于 H。
时间复杂度: O ( n ∗ 2 n ∗ l o g a n s ) O(n*2^n*log\ ans) O(n∗2n∗log ans)
从小到大枚举所有集合,对于当前集合,遍历所有不在该集合的事件,用该集合的状态 更新 加上该事件后集合的状态:
为了使得伤害最大,每个技能都在最小能释放的时间释放。
当前技能释放的最小时间为,集合中所有技能的冷却时间之和。伤害从释放的时间开始,到释放时间 + len[i] - 1 结束,结束时间要和二分的时间 T 取 min。f[i | 1 << j] = max(f[i | 1<<j], f[i] + dmg[j][min(end-sum, len[j]-1)]);
最后时间卡的很紧,要剪剪枝。
1.枚举所有集合的时候,如果当前集合都没有被更新过,那就不用再去更新其他集合了,直接跳过。所以初始化将所有状态初始为-1,0状态初始为0。如果集合状态为 -1 就跳过。因为其要更新的集合已经被 0 状态更新过了。
2.当前伤害满足后立刻退出,没必要更新完所有集合了。
3.也可以把每个集合的冷却时间总和预处理出,这样就不用每次循环求了。
Code
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define int long long
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];
int t[20], len[20];
int dmg[20][N];
int f[1<<18];
bool check(int mid)
{
int end = mid;
mem(f, -1);
f[0] = 0;
for(int i=0;i<1<<n;i++)
{
if(f[i] == -1) continue;
int sum = 0;
for(int j=0;j<n;j++) if(i >> j & 1) sum += t[j]; //可以将此块预处理
if(sum > end) continue;
for(int j=0;j<n;j++)
{
if(i >> j & 1) continue;
f[i | 1 << j] = max(f[i | 1<<j], f[i] + dmg[j][min(end-sum, len[j]-1)]);
if(f[i | 1<<j] >= m) return 1;
}
}
return 0;
}
signed main(){
Ios;
cin >> T;
while(T--)
{
cin >> n >> m;
int l = 0, r = 0;
for(int i=0;i<n;i++) //用到状压时数组位置尽量从0开始
{
cin >> t[i] >> len[i];
for(int j=0;j<len[i];j++)
{
cin >> dmg[i][j];
if(j) dmg[i][j] += dmg[i][j-1];
}
r += t[i] + len[i] - 1; //最大时间
}
while(l < r)
{
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
if(check(l)) cout << l << endl;
else cout << -1 << endl;
}
return 0;
}
很好的一道结合题!
边栏推荐
- 对均匀采样信号进行重采样
- Mysql版本升级,直接复制Data文件,查询特别慢
- 小程序毕设作品之微信二手交易小程序毕业设计成品(8)毕业设计论文模板
- The curl command to get the network IP
- Solve the problem of compiling and installing gdb-10.1 unistd.h:663:3: error: #error “Please include config.h first.”
- How to compare struct, slice, map for equality and the difference between several comparison methods in golang
- 函数的底层机制
- Mini Program Graduation Works WeChat Second-hand Trading Mini Program Graduation Design Finished Works (3) Background Functions
- Eureka Registry
- Pytorch框架学习记录3——Transform的使用
猜你喜欢
SQL introduction of the first lecture -- MySQL 8.0.29 installation tutorial (Windows 64 - bit)
宇宙的尽头是银行?聊聊在银行做软件测试的那些事
redis分布式锁的原子保证
小程序毕设作品之微信二手交易小程序毕业设计成品(8)毕业设计论文模板
Hongji was once again shortlisted in the Gartner 2022 RPA Magic Quadrant and achieved a significant jump in position
Wechat second-hand transaction small program graduation design finished product (1) Development overview
PyG搭建R-GCN实现节点分类
为什么突然间麒麟 9000 5G 版本,又有库存了?
forward与redirect的区别
一起来学习flutter 的布局组件
随机推荐
Taobao/Tmall get Taobao store details API
flutter 记录学习不一样的动画(二)
数组和结构体
2022.7.29-----leetcode.593
恐造成下一个“千年虫”的闰秒,遭科技巨头们联合抵制
Redis server启动后会做哪些操作?
Pytorch framework to study record 6 - the torch. Nn. The Module and the torch nn. Functional. The use of conv2d
Eureka Registry
【C进阶】数组传参与函数指针
Mysql版本升级,直接复制Data文件,查询特别慢
2022-07-29 Group 4 Self-cultivation class study notes (every day)
cv2.polylines
(redistribute, special comprehensive experiment ospf area)
逆向理论知识3【UI修改篇】
宇宙的尽头是银行?聊聊在银行做软件测试的那些事
Why is the Kirin 9000 5G version suddenly back in stock?
spicy(一)基本定义
Transformation of traditional projects
TCP congestion control technology and acceleration principle of BBR
CMake installation and testing