zoukankan      html  css  js  c++  java
  • P3724 [AH2017/HNOI2017]大佬 [模拟(?), 单调性]

    大佬

    题目描述见链接 .


    color{red}{正解部分}

    目标是 活着 使大佬自信心变为 00,

    首先可以发现 一组进攻 在固定的 天数 内, 其产生的效果是相同的,
    而 能进攻的天数 越多, 其 “胜算” 越大, 所以考虑先求出 最大活动天数,
    这可以使用 dpdp 求解, 设 F[i,j]F[i, j] 表示前 ii 天, 第 iihphpjj 时能够 活动 的最大天数,
    考虑 F[i,j]F[i, j] 能够更新的状态:

    • F[i+1,jai+1]=max(F[i,j]+1)F[i+1,j-a_{i+1}] = max(F[i,j]+1)
    • F[i+1,min(MC, jai+1+wi+1)]=max(F[i,j])F[i+1, min(MC, j-a_{i+1}+w_{i+1})] = max(F[i, j])

    然后取 max(F[i,j])max(F[i,j]) 为最大 活动 天数, 记为 MdMd,

    注意不是 max(F[N,j])max(F[N, j]), 因为也可以在 NN 天前击败大佬 .

    接下来使用 BFSBFS 配合 哈希表判重 处理出所有的 招式 二元组 (d,f)(d, f),

    由于每次攻击力至少增加 11 倍, 因此攻击力的状态数是 O(logC)O(log C) 级别的, dd 的状态数是 O(N)O(N) 级别的, 总状态数至少为 O(NlogC)O(Nlog C), 小于 O(N2)O(N^2), 开 O(N2)O(N^2) 的状态数组即可 .

    表示花费 dd 天, 造成 ff 的伤害, 且至多含有一次拔刀的招式, 接下来分情况讨论,

    • 不拔刀, 需满足 MdCMd geq C .
    • 可能拔一次刀, 需满足 CfC geq fMddCfMd-d geq C-f
    • 可能拔两次刀, 需满足 Cf1+f2C geq f_1 + f_2Mdd1d2Cf1f2Md-d_1-d_2 geq C-f_1-f_2 .

    22 种情况很好判断, 考虑如何处理第 33 个情况,

    ff 为第一关键字 从小到大 排序, 从右向左 枚举指针 ii 表示 (f1,d1)(f_1, d_1), 然后再维护一个指针 jj 从左向右 移动, 表示 (f2,d2)(f_2, d_2), 移动过程中始终保持 Cf1+f2C geq f_1 + f_2,

    目的是满足条件: Mdd1d2Cf1f2Md-d_1-d_2 geq C-f_1-f_2 ightarrow Mdd1+f1Cd2f2Md-d_1+f_1-C geq d_2-f_2
    因此在移动的过程中 在满足 f1+f2Cf_1 + f_2 le C 的前提下 记录 minn=min(d2f2)minn = min(d_2-f_2),
    由于 f1f_1 不断减小, 因此前面合法的 minnminn, 在当前也一定合法,
    于是直接检查 Mdd1+f1CminnMd-d_1+f_1-C geq minn 这个条件是否满足, 若满足, 说明至多拔两次刀可以砍掉大佬 .


    color{red}{实现部分}

    BFSBFS 更新状态时, 有 22 种选择,

    • 升级时无需将当前状态加入 二元组 集合 .
    • 加攻击力时 判重 后加入 BFSBFS队列 和 二元组 集合 .

    注意在判重时可以只判断 (d,f)(d, f) 是否重复, 无需管等级 .

    #include<bits/stdc++.h>
    #define reg register
    #define fi first
    #define se second
    typedef std::pair<int, int> pr;
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 1015;
    
    int N;
    int M;
    int Mc;
    int Md;
    int Max_c;
    int sk_cnt;
    int a[maxn];
    int w[maxn];
    int C[maxn];
    int F[maxn][maxn];
    
    struct Hash_Map{
    
            int num0;
            int mmod;
            int head[maxn*maxn];
    
            struct EDGE{ int nxt, x, y; } edge[maxn*maxn];
    
            void insert(int x ,int y){
                    int from = (1ll*x*29 + y) % mmod;
                    edge[++ num0] = (EDGE){ head[from], x, y };
                    head[from] = num0;
            }
    
            bool count(int x, int y){
                    int from = (1ll*x*29 + y) % mmod;
                    for(reg int i = head[from]; i; i = edge[i].nxt)
                            if(edge[i].x == x && edge[i].y == y) return 1;
                    return 0;
            }
    
    } Mp;
    
    std::pair <int, int> skil[maxn*maxn];
    
    struct Node{ int d, f, lev; } ;
    
    void BFS(){
            std::queue <Node> Q; Q.push((Node){ 1, 1, 0 });
            while(!Q.empty()){
                    Node ft = Q.front(); Q.pop();
                    if(ft.d >= Md) continue ;
                    Q.push((Node){ ft.d+1, ft.f, ft.lev + 1});
                    if(ft.lev<=1 || 1ll*ft.f*ft.lev > Max_c || Mp.count(ft.d+1, ft.f*ft.lev)) continue ;
                    Q.push((Node){ ft.d+1, ft.f*ft.lev, ft.lev });
                    Mp.insert(ft.d+1, ft.f*ft.lev);
                    skil[++ sk_cnt] = pr(ft.f*ft.lev, ft.d+1);
            }
    }
    
    void Work(int x){
            int minn = 0x7f7f7f7f;
            if(C[x] <= Md){ puts("1"); return ; }
            for(reg int i = sk_cnt, j = 1; i >= 1; i --){
                    if(C[x] >= skil[i].fi && Md-skil[i].se >= C[x]-skil[i].fi){ puts("1"); return ; }
                    while(j <= sk_cnt && skil[i].fi+skil[j].fi <= C[x]){ 
                            minn = std::min(minn, skil[j].se - skil[j].fi);
                            j ++;
                    } 
                    if(Md - skil[i].se + skil[i].fi - C[x] >= minn){ puts("1"); return ; }
            }
            puts("0");
    }
    
    int main(){
            N = read(), M = read(), Mc = read();
            for(reg int i = 1; i <= N; i ++) a[i] = read();
            for(reg int i = 1; i <= N; i ++) w[i] = read();
            for(reg int i = 1; i <= M; i ++) Max_c = std::max(Max_c, C[i] = read());
            for(reg int i = 1; i <= N; i ++)
                    for(reg int j = a[i]; j <= Mc; j ++){
                            F[i][j-a[i]] = std::max(F[i][j-a[i]], F[i-1][j] + 1);
                            int &t = F[i][std::min(Mc, j-a[i]+w[i])]; t = std::max(t, F[i-1][j]);
                    }
            for(reg int i = 1; i <= N; i ++)
                    for(reg int j = 1; j <= Mc; j ++) Md = std::max(Md, F[i][j]);
            Mp.mmod = 1e6 + 7; BFS();
            std::sort(skil+1, skil+sk_cnt+1);
            for(reg int i = 1; i <= M; i ++) Work(i);
            return 0;
    }
    
  • 相关阅读:
    find 按文件修改时间查找文件
    Single- and Multichannel Memory Modes
    Jeff Dean Facts, Haha
    技巧:多共享动态库中同名对象重复析构问题的解决方法
    Processor technologies
    内存模型系列(上)- 内存一致性模型(Memory Consistency)
    python协程
    mysql学习笔记(1)
    python爬虫-----Python访问http的几种方式
    python基础 pyc
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822428.html
Copyright © 2011-2022 走看看