2023 ICPC 网络赛 第二场 部分题解 (待完善)

news/2024/7/5 1:37:36

D Project Manhattan

思路:

最终选中的下标,必然包含n个行或者n个列.

所以答案 = n行的最小值之和或者n列的最小值之和

注意坑点: 当存在负数时,应该把负数全部选上,答案只会更优.

代码:

#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define int long long
#define endl '\n'
#define bit(x) (1ll << x)
using namespace std;
const int N = 1e6 + 5;
const int inf = 1e16;
void solve()
{
    int n;
    cin >> n;
    vector<vector<int>> a(n + 1, vector<int>(n + 1));
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cin >> a[i][j];
        }
    }

    int ans1 = 0;
    int ans2 = 0;
    for (int i = 1; i <= n; i++)
    {
        vector<int> c(n + 1);
        for (int j = 1; j <= n; j++)
        {
            c[j] = a[i][j];
        }
        sort(c.begin() + 1, c.end());
        ans1 += c[1];
        int now = 2;
        while (c[now] < 0)
        {
            ans1 += c[now];
            now++;
        }
    }

    for (int i = 1; i <= n; i++)
    {
        vector<int> c(n + 1);
        for (int j = 1; j <= n; j++)
        {
            c[j] = a[j][i];
        }
        sort(c.begin() + 1, c.end());
        ans2 += c[1];
        int now = 2;
        while (c[now] < 0)
        {
            ans2 += c[now];
            now++;
        }
    }
    cout << min(ans1,ans2) << endl;
}
signed main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

E Another Bus Route Problem

题解:

下面这些话比较抽象, 具体看代码.

记忆化BFS.

对于一条路径(u,v), 不断的找他们的LCA,并标记中途经过的点,如果途中经过的点是线路的话,就加入队列中,然后把步数+1即可.

会有两种情况:

1.整条路径(u,v)都没有被访问过:直接标记即可

2.找LCA的过程中,已经有顶点被标记过了.那么说明他们的LCA也必然被标记过了,否则不可能出现这种状态.没被标记的那个条路径继续往上找.

#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define int long long
#define endl '\n'
#define bit(x) (1ll << x)
using namespace std;
const int N = 1e6 + 5;
const int inf = 1e16;
vector<int> g[N];
vector<int> fa(N);
vector<int> dep(N);
map<int, vector<pair<int, int>>> path;
vector<int> vis(N); // 标记
void dfs(int u)
{
    dep[u] = dep[fa[u]] + 1;
    for (auto v : g[u])
    {
        fa[v] = u;
        dfs(v);
    }
}
void solve()
{
    int n, m;
    cin >> n >> m;
    for (int i = 2; i <= n; i++)
    {
        int x;
        cin >> x;
        g[x].push_back(i);
    }
    dfs(1);//LCA需要得到每个顶点的深度,
    for (int i = 1; i <= m; i++)//把路径存到两个端点上
    {
        int u, v;
        cin >> u >> v;
        path[u].push_back({u, v});
        path[v].push_back({u, v});
    }
    queue<array<int, 3>> q;
    for (int i = 0; i < path[1].size(); i++)//起点肯定是从1号开始的
    {
        q.push({path[1][i].first, path[1][i].second, 1});
    }
    vis[0] = 1e5;//无效状态,直接标记
    while (q.size())
    {
        int left = q.front()[0];
        int right = q.front()[1];
        int step = q.front()[2];//到当前路径(left,right)的转站步数
        q.pop();
        while (left != right && !vis[left] && !vis[right])//找LCA,如果出现已经访问过的点,直接停止
        {
            if (dep[left] < dep[right])
            {
                vis[right] = step;//标记路径
                for (int i = 0; i < path[right].size(); i++)//该点存在路径直接存进去
                {
                    q.push({path[right][i].first, path[right][i].second, step + 1});
                }
                right = fa[right];//往上走
            }
            else
            {
                vis[left] = step;
                for (int i = 0; i < path[left].size() ; i++)
                {
                    q.push({path[left][i].first, path[left][i].second, step + 1});
                }
                left = fa[left];
            }
        }
        //如果还没到LCA就终止了,说明他们的LCA已经被访问过了.
        while (!vis[left])//如果没被访问过,就一直往上标记,到达LCA或标记过的点就会停止
        {
            vis[left] = step;
            for (int i = 0; i < path[left].size() ; i++)
            {

                q.push({path[left][i].first, path[left][i].second, step + 1});
            }
            left = fa[left];
        }
        while (!vis[right])//如果没被访问过,就一直往上找
        {
            vis[right] = step;
            for (int i = 0; i < path[right].size() ; i++)
            {

                q.push({path[right][i].first, path[right][i].second, step + 1});
            }
            right = fa[right];
        }
    }
    for (int i = 2; i <= n; i++)
    {
        if (!vis[i])
        {
            cout << -1 << " ";
            continue;
        }
        cout << vis[i] << " ";
    }
    cout << endl;
}
signed main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    // cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

M Dirty Work

题解:

写完一道题的期望时间是 ai + bi*pi

把n道题的期望时间从小到大排序,然后按顺序完成题目即可.

#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define int long long
#define endl '\n'
#define bit(x) (1ll << x)
using namespace std;
const int N = 1e6 + 5;
const int inf = 1e16;
void solve()
{
    int n;
    cin >> n;
    vector<double> ans(n+1);
    for(int i = 1; i<=n; i++)
    {
        double a,b,p;
        cin >> a >> b >> p;
        ans[i] = a + 1.0*b*p;
    }
    sort(ans.begin()+1,ans.end());
    double sum =0;
    for(int i=1; i<=n; i++)
    {
        ans[i]+=ans[i-1];
        sum+=ans[i];
    }
    printf("%.10lf\n",sum);
}
signed main()
{
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

I Impatient Patient

题解:

标签:期望方程.

设dp[i]表示从i直接到达终点的期望天数

1. 成功的概率是 pi,直接到达终点

贡献是 :pi*1

2.失败的概率是 1-pi,那么从i点回到a[i]点,然后从a[i]点再到 i号点

贡献是 :(1-pi) * (i- a[i] +1 + dp[i])

综上,得到期望方程

dp[i] = pi + (1-pi) * (i- a[i] +1 + dp[i])

化简得:   dp[i] = ( p + (1-p)*(i-a[i]+1) )  /p;  

#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define int long long
#define endl '\n'
#define bit(x) (1ll << x)
using namespace std;
const int N = 1e6 + 5;
const int inf = 1e16;

void solve()
{
    int n;
    cin >> n;
    vector<int> a(n + 2), q(n + 2);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        a[i]++;
    }
    for (int i = 1; i <= n; i++)
    {
        cin >> q[i];
    }
    vector<double> dp(n + 2);
    double ans = n;
    for (int i = 1; i <= n; i++)
    {
        double p = q[i]/(1.0*100000);//成功概率
        dp[i] = ( p + (1-p)*(i-a[i]+1) )  /p;//从i到n+1点的期望天数
        ans = min(ans,i-1+dp[i]);
    }
    printf("%.12lf\n", ans);
}
signed main()
{
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

L Super-palindrome

题解:

先陈述一下最小公共前后缀的概念

比如字符串 :abc]defabcabcdef abc 

该字符串的最小公共前后缀为3:[abc] defabcabcdef [abc]  

字符串: ababababab

该字符串的最小公共前后缀为2: [ab]ababab[ab]

样例字符串: pbbp

该字符串的最小公共前后缀为2: [pb][pb]

设dp[l][r]表示区间[l,r] 是否是超级字符串.

nxt[id][i]表示在字符串 s[id]...s[n]中 以第i个字母为右端点的最小公共前后缀.

转移方程:

dp[l][r] |= dp[l+ Min][r-Min];  //其中 Min表示 字符串s [l,r]的最小公共前后缀.

举例说明:

样例说明:

问字符串[pb]pbpb[pb]是否是超级回文串?

最小公共前后缀[pb]可以成功匹配,所以只要看里面 pbpb 是否是超级回文串即可.

代码:

#include <bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define int long long
#define endl '\n'
#define bit(x) (1ll << x)
using namespace std;
const int N = 1e6 + 5;
const int inf = 1e16;
const int maxn = 5e3 + 10;
// nxt数组表示 以i为右端点的最短公共前后缀
int nxt[maxn][maxn];
void Min_kmp(string a, int id) // 传入的下标一定是从0开始的
{

    a = " " + a;
    int n = a.size() - 1;
    for (int i = 0; i <= n; i++)
    {
        nxt[id][i] = 0;
    }
    for (int i = 2, j = 0; i <= n; i++)
    {
        while (j && a[i] != a[j + 1])
            j = nxt[id][j];
        if (a[i] == a[j + 1])
            j++;
        nxt[id][i] = j;
    }
    for (int i = 2, j = 2; i <= n; i++, j = i)
    {
        while (nxt[id][j])
            j = nxt[id][j];
        if (nxt[id][i])
            nxt[id][i] = j;
    }
    for (int i = 0; i < n; i++)
    {
        nxt[id][i] = nxt[id][i + 1];
    }
    nxt[id][n] = 0;
}
int dp[maxn][maxn];
void solve()
{

    string s;
    cin >> s;
    int n = s.size();
    for(int i = 0; i<=n; i++)
    {
        for(int j = 0; j<=n; j++)
        {
            dp[i][j] = 0;
        }
    }
    for (int i = 0; i < s.size(); i++)
    {
        string t = s.substr(i);
        Min_kmp(t, i);//找到以s[i]为起点字符串的最小公共前后缀
    }
    int ans = 0;
    for (int len = 2; len <= n; len++)
    {
        for (int l = 0; l < n; l++)
        {
            int r = l + len - 1;
            int Min = nxt[l][r - l];//以s[l...r]中以r为右端点的最小公共前后缀
            if (Min * 2 == len)//直接拼接即可
            {
                dp[l][r] |= 1;
            }
            dp[l][r] |= dp[l + Min][r - Min];
            if (dp[l][r])
            {
                ans++;
            }
        }
    }
    cout << ans << endl;
}
signed main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}


http://lihuaxi.xjx100.cn/news/1572914.html

相关文章

【ccf-csp题解】第5次csp认证-第三题-模板生成系统-字符串模拟

题目描述 思路分析 这个是一个简单的字符串模拟题&#xff0c;但蕴藏了一些细节值得挖掘&#xff0c;故写于博客之中进行记录。 第一、关于数据的读入 对于前m行&#xff0c;直接使用getline函数进行读入即可&#xff0c;注意在读取完m和n之后&#xff0c;要写一个getchar&a…

最长连续递增子序列

给定一个顺序存储的线性表&#xff0c;请设计一个算法查找该线性表中最长的连续递增子序列。例如&#xff0c;(1,9,2,5,7,3,4,6,8,0)中最长的递增子序列为(3,4,6,8)。 输入格式: 输入第1行给出正整数n&#xff08;≤105&#xff09;&#xff1b;第2行给出n个整数&#xff0c;…

微调大模型工具-LoRA

介绍 微调 在机器学习领域&#xff0c;大型模型已成为解决各种问题的首选解决方案。从自然语言处理到计算机视觉&#xff0c;这些计算能力的庞然大物都表现出了无与伦比的性能。然而&#xff0c;这种性能实际上是有代价的。微调这些大型模型以适应特定任务或领域是一个资源密…

web前端项目案例实战

之前也有使用vite2vue3electronc创建桌面端项目&#xff0c;不过 vue-cli-plugin-electron-builder 脚手架插件构建的项目electron版本只有13.x。如今electron版本都到了24&#xff0c;显然不能再用之前的方法创建项目了。于是闲暇时间就捣鼓了electron24vite4搭建桌面程序&…

Ubantu GoLand安装

下载GoLand 下载Linux版的压缩包 解压到usr/local tar -C /usr/local -xzf gox.x.x.linux-amd64.tar.gz -xzf 后面是下载goland的全名 确保golang 已经正常安装&#xff0c;参考Golang Linux 安装与环境变量配置_一零壹0的博客-CSDN博客 启动GoLand cd 到解压目录下 cd …

数据链路层协议

文章目录 数据链路层协议0. 数据链路层解决的问题1. 以太网协议(1) 认识以太网(2) 以太网帧格式<1> 两个核心问题 (3) 认识MAC地址(4) 局域网通信原理(5) MTU<1> 认识MTU<2> MTU对IP协议的影响<3> MTU对UDP协议的影响<4> MTU对TCP协议的影响<…

Flex布局实战

Flex布局简介 Flex布局是一种用于网页布局的现代CSS布局模型。它使用flex容器和flex项来实现灵活的、响应式的布局。Flex容器是父元素&#xff0c;内部包含一系列的flex项。Flex项可以根据指定的规则自动调整尺寸和位置&#xff0c;以适应不同的屏幕大小和设备类型。 Flex布局…

12大常用自动化测试工具,请记得转发收藏!

常用自动化测试工具 1、Appium AppUI自动化测试 Appium 是一个移动端自动化测试开源工具&#xff0c;支持iOS 和Android 平台&#xff0c;支持Python、Java 等语言&#xff0c;即同一套Java 或Python 脚本可以同时运行在iOS 和Android平台&#xff0c;Appium 是一个C/S 架构&…