首页 > 其他分享 >08-02 题解

08-02 题解

时间:2024-08-06 14:50:51浏览次数:5  
标签:02 10 int 题解 08 long defeat id dp

<head> <script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"></script> <script type="text/x-mathjax-config"> MathJax.Hub.Config({ tex2jax: { skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'], inlineMath: [['$','$']] } }); </script> </head>

08-02 题解

模拟赛

A

首先, 这题的 dp 不满足四边形不等式, 这告诉我们猜决策单调性的时候多打几个样例看看(不过这么着过了是真抽象)

朴素的想法

题意转化:

如果每份伤害为 \(i\), 你能打败 \(defeat_i\) 个怪物, 求选出 \(n\) 个 \(i\) 使得他们的和为 \(m\) , \(\sum_{i \in S} defeat_i\) 最大, 输出 \(n - \frac{\sum_{i \in S} defeat_i}{n}\)

设 \(f(x, y)\) 表示选了 \(x\) 个 \(i\), \(i\) 的和为 \(y\), \(\sum defeat\)的最大值为 \(f(x, y)\)

这样转移是 \(nm^2\) 的

考虑怎么优化

方法1: max+ 卷积

何为 max+ 卷积 ?

形如本题的转移式 dp[i][j] = max(dp[i - 1][k] + defeat[j - k]) , 即外层为 max 操作, 内层为 + 操作

max+ 卷积有什么好的性质?

他是符合结合律的

感性理解一下, dp[i][j] 里面先加入了 2 个defeat, 再加了 1 个, 这和先 1 后 2 的最优答案是一样的

(上述内容可结合 01 背包理解 : 背包的最终答案和物品放入顺序无关)

这样的性质就让我们可以倍增的去做

类似快速幂地, defeat 数组相当于底数, dp 数组相当于 ans

然后就做完了, 代码实现不难

方法2: 剪枝

设当前加进去的攻击值为 \(x\)

如果把 \(x\) 从大往小加进去, 那么 当前已经选的份数 \(i \le \lfloor \frac{m}{i} \rfloor\)

所以对于 \(x \in [0, m]\) , \(i\) 的循环次数 \(\sum_i = \lfloor \frac{m}{1} \rfloor + \lfloor \frac{m}{2} \rfloor + ... + \lfloor \frac{m}{m} \rfloor\)

这是个调和级数, 所以枚举 \(i\) 一共 \(m\ log\ m\)次, 总复杂度是 \(O(m^2 + m\ log\ m)\) (我分析的对吗? 感觉有 bug)

然后就过了

代码

方法一

#include <bits/stdc++.h>
#define int long long
#define double long double
#pragma optimize(3)
using namespace std;
const int N = 1e3 + 10, M = 5e3 + 10;

int n, m;
int a[N];
double dp[M], defeat[M];

void Max_Plus(int ti){
    while(ti){
        if(ti & 1){
            for(int i = m; i >= 0; i--){
                dp[i] += defeat[0];
                for(int j = 1; j <= i; j++){
                    dp[i] = max(dp[i], dp[i - j] + defeat[j]);
                }
            }
        }
        ti >>= 1;
        for(int i = m; i >= 0; i--){
            defeat[i] += defeat[0];
            for(int j = 1; j < i; j++){ //每个 i 只能卷一次 0
                defeat[i] = max(defeat[i], defeat[i - j] + defeat[j]);
            }
        }
    }
}

signed main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }

    for(int i = 0; i <= m; i++){
        for(int j = 1; j <= n; j++){
            defeat[i] += (a[j] <= i);
        }
    }

    Max_Plus(n);
    double ans = n - 1.0 * dp[m] / n;
    printf("%.10Lf\n", ans);
}

方法二

#include <bits/stdc++.h>
#pragma optimize(3)
using namespace std;
const int N = 1e3 + 10, M = 5e3 + 10;

int n, m;
int a[N];
int dp[M][N], defeat[M];

signed main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }

    for(int i = 0; i <= m; i++){
        for(int j = 1; j <= n; j++){
            defeat[i] += (a[j] <= i);
        }
    }

    dp[0][0] = 0;
    for(int i = m; i >= 0; i--){
        for(int j = 0; j <= m; j++){
            for(int k = 1; k <= ((i == 0) ? n : min(n, m / i)); k++){
                if(j < i) continue;
                dp[j][k] = max(dp[j][k], dp[j - i][k - 1] + defeat[i]);
            }
        }
    }
    double ans = n - 1.0 * dp[m][n] / n;
    printf("%.10lf\n", ans);
}

B

这道题和前几天 HackerRank 的那个不同, 本题字典序最小的路径是唯一的, 因为点的编号各不相同

首先, 我们不可能把所有路径存下来, 最劣\(n^2m\) 的空间

因为路径唯一, 即 w 如果在 u, v 的路径上, 那么 (w, v) 是 (u, v) 的一部分, 这说明路径信息是可合并的

所以考虑倍增

设 \(f(i, j, k)\) 为以 \(i\) 为起点, \(j\) 为终点的路径上第 \(2^k\) 个点的编号

\(f(i, j, k) = f(f(i, j, k - 1), j, k - 1)\), 感性理解就好

发现终点 \(j\) 在转移式里是不变的

所以枚举终点 \(j\) , 对于每个 \(i\) , 保留他能到达 \(j\) 的字典序最小的出边, 建反图

这样做能保证走环的情况为-1, 因为在反图上两点根本不可达, 记录一下即可

然后就做完了

代码

#include <bits/stdc++.h>
#pragma optimize(3)
using namespace std;
const int N = 2e3 + 10;

int n, m, q, type;
int u, v, s, t, k;
vector <int> e[N], ee[N];

int f[N][N][12], dis[N][N];
bool vis[N][N];

void Dfs(int x, int id){
    vis[id][x] = 1;
    for(auto i : e[x]){
        if(vis[id][i]) continue;
        Dfs(i, id);
    }
}

void Dfs2(int x, int id){
    for(auto i : ee[x]){
        if(i == id) continue;
        dis[id][i] = dis[id][x] + 1;
        Dfs2(i, id);
    }
}

signed main(){
    cin >> n >> m >> q >> type;

    for(int i = 1; i <= m; i++){
        cin >> u >> v;
        e[u].push_back(v);
    }

    for(int i = 1; i <= n; i++){
        Dfs(i, i);
    }

    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            ee[j].clear();
        }
        for(int j = 1; j <= n; j++){
            int mini = n + 1;
            for(auto k : e[j]){
                if(vis[k][i]){
                    mini = min(mini, k);
                }
            }
            if(vis[j][i]){
                ee[mini].push_back(j);
                f[j][i][0] = mini;
            }
        }

        Dfs2(i, i);
        for(int j = 1; j <= 11; j++){
            for(int k = 1; k <= n; k++){
                f[k][i][j] = f[f[k][i][j - 1]][i][j - 1];
            }
        }
    }

    int lstans = 1;
    for(int i = 1; i <= q; i++){
        cin >> s >> t >> k;
        if(type){
            s = (s ^ lstans) % n + 1;
            t = (t ^ lstans) % n + 1;
            k = (k ^ lstans) % n + 1;
        }

        if(s == t && k == 1){
            cout << s << "\n";
            lstans = s;
            continue;
        }

        --k;
        if(dis[t][s] < k || !dis[t][s]){
            cout << "-1\n";
            lstans = 1;
            continue;
        }

        for(int j = 11; j >= 0; j--){
            if((k >> j) & 1){
                s = f[s][t][j];
            }
        }
        lstans = s;
        cout << s << "\n";
    }
}

C

代码貌似非常麻烦, 不想写, 这里只说一下第一步转化

对于 \(l\), \(r\) 我们肯定要从 \(l\) 走到 \(r\), 在中间出现一些 \(i \to i-1\ \to i\) 的折返, 每一步这样的折返可以使 \(a_i\), \(a_{i + 1}\) 各减少 1

设折返步数数组 \(b_i\), 含义如上

首先对所有 \(a\) 减 1, 这是主线(\(l \to r\)) 的贡献

\(b_l = a_l\)

\(b_i = a_i - b_{i - 1}\)

如果 \(b_r\) 不为 0, 则无解

如果任意 \(i \in [l, r]\), \(b_i < 0\) , 那么也无解

然后你就得到了一种优秀的 \(n^2\) 做法哈哈哈(但是因为数据过水, 你能获得 60 pts 的好成绩)

代码

#include <bits/stdc++.h>
#define int long long
#define double long double
#pragma optimize(3)
using namespace std;
const int N = 1e6 + 10;

int n, q;
int a[N], opt, l, r, x;
int ca[N], b[N];

signed main(){
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }

    cin >> q;
    for(int i = 1; i <= q; i++){
        cin >> opt >> l >> r;
        if(opt == 1){
            cin >> x;
            for(int j = l; j <= r; j++){
                a[j] += x;
            }
        }else{
            for(int j = l; j <= r; j++){
                ca[j] = a[j] - 1;
            }

            b[l] = ca[l];
            for(int j = l + 1; j <= r; j++){
                b[j] = ca[j] - b[j - 1];
            }

            bool f = 1;
            for(int j = l; j <= r; j++){
                if(b[j] < 0){
                    f = 0;
                    break;
                }
            }
            if(b[r] != 0){
                f = 0;
            }

            if(f == 1){
                cout << "Yes\n";
            }else{
                cout << "No\n";
            }
        }
    }
}

标签:02,10,int,题解,08,long,defeat,id,dp
From: https://www.cnblogs.com/Bubblee/p/18345123

相关文章

  • Mac开发基础08-NSWindow(二)
    NSWindow其他使用和技巧NSWindow是macOS应用程序中用于显示和管理窗口的核心类。可用于创建、编辑和管理应用程序的窗口。1.自定义窗口的内容视图层级替换默认的内容视图NSWindow默认包含一个内容视图,你可以使用自定义内容视图来替换它。Objective-CNSView*customVie......
  • 2024年8月4日 加训
    2024年8月4日加训A\[\lvertS\capT\rvert\inV_{f(T)}\]对于一个\(T\),限制形如\(T\)中的元素有\(V_{f(T)}\)个,求\(T\)的大小为各种的子集,并将其设置为不合法\(g(S)\)集合\(S\)是否合法规约不来。不会正解枚举\(S\),然后相应地规约限制B看起来像支配一类的问......
  • 洛谷P1081【NOIP2012提高组】开车旅行
    题目见[NOIP2012提高组]开车旅行-洛谷(懒得打题目了)我们直接上代码#include<iostream>#include<cstdlib>#include<cstdio>#include<cmath>#include<cstring>#include<iomanip>#include<algorithm>#include<ctime>#include<queue>......
  • 笔记本CPU天梯图(2024年8月),含AMD/骁龙等新CPU
    原文地址(高清无水印原图/持续更新/含榜单出处链接):2024年8月笔记本CPU天梯图2024年8月笔记本CPU天梯图2024年8月5日更新日志:常规更新CinebenchR23、PassMark笔记本CPU天梯图,新增Geekbench6.2单核多核天梯图(Notebookcheck);移除鲁大师天梯图。----------手动分割线------......
  • Dreamweaver (DW)2021 下载 安装
    将 Dreamweaver2021 压缩包解压到本地:点击蓝色字体下载压缩包提取码ixsu鼠标右键点击 Set-up 选择 以管理员身份运行:点击 更改位置 可以自定义选择安装路径 也可以选择默认位置点击 继续:等待安装正常等待5分钟左右:安装完成点击关闭:双击桌面 Drea......
  • 20240806:点分治,虚树选做
    POJ-1741Tree题意:给定一棵树,求多少无序对\((u,v)\)满足\(\text{dist}(u,v)\lek\)。对于树上的路径进行分类:经过根;不经过根。第二类路径点可以通过递归子树求出。对于经过根的路径,可以一遍dfs求出每个点到根的距离\(\text{dis}(u)\)。问题转化为求\(\text{dis}(u)......
  • CVE-2023-7130漏洞靶场复现
    CollegeNotesGallery2.0允许通过“/notes/login.php”中的参数‘user’进行SQL注入。利用这个问题可能会使攻击者有机会破坏应用程序,访问或修改数据.抓登录包放sqlmap爆破直接--dump一把梭哈......
  • CVE-2023-0562银行储物柜管理系统登录页面sql注入漏洞靶场复现
    在PHPGurukul银行储物柜管理系统1.0中发现了一个漏洞。它被评定为临界状态。受此问题影响的是组件登录的文件index.php的一些未知功能。对参数username的操作会导致sql注入。攻击可能是远程发起的。该漏洞已被公开,并可能被利用。此漏洞的标识符是VDB-219716。抓登录包放salmap......
  • 2000-2023年上市公司财务困境数据合集(ZScore、RLPM、MertonDD、OScore)(含原始数据+计算
    2000-2023年上市公司财务困境数据合集(ZScore、RLPM、MertonDD、OScore)(含原始数据+计算结果)1、时间:2000-2023年2、来源:上市公司年报3、范围:A股上市公司4、指标:MertonDD模型:证券代码、证券简称、统计截止日期、是否发生ST或*ST或PT、是否发生暂停上市、行业代码、行业名称......
  • 1990-2023年上市公司常用变量数据(1400+指标)
    1990-2023年上市公司常用变量数据(1400+指标)1、时间:1990-2023年2、范围:上市公司3、格式:dta4、来源:上市公司年报5、指标:包括上市公司基本信息(性质、行业、地址)、财务状况(资产负债、利润表、现金流量、偿债能力、披露财务、比率结构、经营能力、盈利能力、现金流量、风险水平......