• [二分][状压dp]Boss Rush 2022杭电多校第3场 1002


    Finally, Little Q gets his weapon at level 10^5105 in the RPG game, now he is trying to beat the boss as soon as possible. The boss has HH units of health point (HP), Little Q needs to cause at least HH units of damage to beat the boss.

    Little Q has learnt nn skills, labeled by 1,2,\dots,n1,2,…,n. Each skill can not be used multiple times, because there is not enough time for Little Q to wait for the skill to cool down. Assume Little Q uses the ii-th skill at the xx-th frame, the actor controlled by him will take t_iti​ frames to perform, which means Little Q will not be allowed to use other skills until the (x+t_i)(x+ti​)-th frame. The length of the damage sequence of the ii-th skill is len_ileni​, which means the skill will cause d_{i,j}di,j​ (0\leq j < len_i0≤j
    The game starts at the 00-th frame. Your task is to help Little Q beat the boss as soon as possible, or determine Little Q can't beat the boss using all the skills at most once.

    Input

    The first line contains a single integer TT (1 \leq T \leq 1001≤T≤100), the number of test cases. For each test case:

    The first line contains two integers nn and HH (1 \leq n \leq 181≤n≤18, 1\leq H\leq 10^{18}1≤H≤1018), denoting the number of skills and the HP of the boss.

    For each skill, the first line contains two integers t_iti​ and len_ileni​ (1 \leq t_i,len_i\leq 100\,0001≤ti​,leni​≤100000), the second line contains len_ileni​ integers d_{i,0},d_{i,1},\dots,d_{i,len_i-1}di,0​,di,1​,…,di,leni​−1​ (1\leq d_{i,j}\leq 10^91≤di,j​≤109).

    It is guaranteed that the sum of all len_ileni​ is at most 3\,000\,0003000000, and there are at most 55 cases such that n>10n>10.

    Output

    For each test case, output a single line containing an integer, denoting the first frame to beat the boss. If it is impossible to beat the boss, please print ''\texttt{-1}-1'' instead.

    Sample

    InputOutput
     
    3 
    1 100 
    5 3 
    50 60 70 
    2 100 
    2 3 
    40 40 100 
    100 2 
    20 5 
    1 1000 
    1 1 
    999
     
    1 
    2 
    -1

    题意: 给出Boss的血量以及你可以使用的n个技能,每个技能最多用一次,并且每个技能使用完后有一段真空期ti不能释放其他技能,每个技能可以造成持续伤害,一共持续len秒,每秒造成di伤害,问最早击败Boss的时间,时间从0开始计算。

    分析: 观察题目发现技能个数很小,所以猜测可以状压dp来枚举技能释放顺序,另外为了求最早击败时间,所以可以二分时间,然后check一下在这个时间内能否击败Boss,check函数里面就是一个状压dp求最大伤害的过程,这个过程和常规状压dp类似,就是枚举上一次释放的技能,只是在计算伤害的时候需要注意留给当前技能的剩余时间,设x表示二分的时间,t表示留给当前技能的时间,为了简化判断的过程,可以预处理出来一个数组time[i],记录i这个状态需要的真空期加和,那么t就等于x-time[上一个状态],t的取值有三种情况,第一种为负数,这说明现在还处于上一个技能的真空期中,那显然此时能造成的伤害就是上一个状态的伤害,第二种情况t∈[0, len],len是当前技能持续时间,这说明该技能伤害只打出来了一部分,此时造成伤害就是上一个状态伤害加该技能伤害的sum[t],第三种情况t > len,这说明该技能伤害全部打满,此时伤害就是上一个状态伤害加该技能sum[len],这三种情况考虑不全很容易出错!

    每次更新完一个状态的伤害dp[i]后都可以和hp比较一下,如果大于等于hp那就说明x时间内可以击败Boss,如果没有状态能击败,那就说明x时间内不能击败Boss,最后输出二分结果即可。

    具体代码如下:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #define int long long
    8. using namespace std;
    9. int n, hp, dp[1<<20], time[1<<20];
    10. struct node{
    11. int t, len;
    12. int sum[100005];
    13. }ski[20];
    14. int st;
    15. bool check(int x){//在x时间内是否可以ko
    16. for(int i = 0; i < 1<
    17. dp[i] = 0;
    18. for(int j = 1; j <= n; j++){
    19. if(i&(1<<(j-1))){
    20. int t = x-time[i^(1<<(j-1))];
    21. if(t < 0) dp[i] = max(dp[i], dp[i^(1<<(j-1))]);
    22. else{
    23. if(t > ski[j].len) t = ski[j].len;
    24. dp[i] = max(dp[i], dp[i^(1<<(j-1))]+ski[j].sum[t]);
    25. }
    26. }
    27. }
    28. st = i;
    29. if(dp[i] >= hp) return true;
    30. }
    31. return false;
    32. }
    33. signed main()
    34. {
    35. int T;
    36. cin >> T;
    37. while(T--){
    38. scanf("%lld%lld", &n, &hp);
    39. int l = 0, r = 0, ans = -1;
    40. for(int i = 1; i <= n; i++){
    41. scanf("%lld%lld", &ski[i].t, &ski[i].len);
    42. r += max(ski[i].t, ski[i].len);
    43. for(int j = 1; j <= ski[i].len; j++){
    44. int t;
    45. scanf("%lld", &t);
    46. ski[i].sum[j] = ski[i].sum[j-1]+t;
    47. }
    48. }
    49. for(int i = 0; i < 1<
    50. time[i] = 0;
    51. for(int j = 1; j <= n; j++){
    52. if(i&(1<<(j-1)))
    53. time[i] += ski[j].t;
    54. }
    55. }
    56. while(l <= r){
    57. int mid = l+r>>1;
    58. if(check(mid)){
    59. r = mid-1;
    60. ans = mid;
    61. }
    62. else l = mid+1;
    63. }
    64. if(ans != -1) printf("%lld\n", ans-1);
    65. else puts("-1");
    66. }
    67. return 0;
    68. }

  • 相关阅读:
    Open3D-读取深度图
    【场景化解决方案】OA审批与用友U9数据集成
    SpringBoot项目连接MySQL数据库
    C++通讯录管理系统
    【golang】sync包once 只执行一次代码
    广西柳州机械异形零部件三维扫描3D抄数全尺寸测绘建模-CASAIM中科广电
    【Django】执行查询—创建和修改对象
    ONLYOFFICE 8.0:引领数字化办公新纪元
    坚持了 10 年的 9 个编程好习惯
    mac在vmware version上搭建三台虚拟机并配置网关用以hadoop集群
  • 原文地址:https://blog.csdn.net/m0_55982600/article/details/126024341