codeforces一些题目思路复盘

news2024/12/16 9:40:28

codeforces round 919 dv2 C Partitioning the Array

大致题意,对于n约数i,我们把原数组分成\frac{n}{i}份,并且每份中有i个元素,对于每个分组情况,如果存在一个数m使得数组中元素modm后使得每个部分的数组完全相同,如果存在那么ans ++求ans

这是一道数论题,数论题的关键在于将数学问题用数学公式表示出来,现在考虑如果存在一个数组a_1a_2a_3a_4....a_n是否存在一个整数m使得数组amodm后所有元素相同

对于这个简化的问题首先列出数学公式 对于i\epsilon[1, n]j\epsilon[1, n] i \neq j 有 a_i\equiv a_j modm

对这个同余式子移项后可得到|a_i - a_j|\equiv 0modm,对于这个式子我们得到这样一个结论|a_i - a_j|是可以整除m的。当然m不能为1,现在把这个式子拓展到整个数组,那么就有了所有相邻元素相减的绝对值都应该整除m,并且m不为1,换句话说这些数两两不互质。当然m的最大值就是这些数的gcd了(codeforces round991 div3 F Maximum modulo equality)。

现在再回到这个问题上,这个问题就相当于这个m必须同时满足很多个数组(\frac{n}{i}个,每个子数组中的元素)每个数组求出gcd中,再将这些gcd求总共gcd,只要gcd不为1,就说明ans可以++。当然这里也涉及到时间复杂度的计算,首先的约数预处理O(n\sqrt{n})最外层的for是约数个数,数据范围内最大的约数个数为168个,总之约数的个数都很小。紧接着的两重循环不大会算,但是感觉可以过:(

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 2e5 + 10;

int gcd(int a, int b) {
    return b? gcd(b, a % b): a;
}

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for(int i = 1; i <= n; i ++ ) cin >> a[i];
    vector<int> divi;
    for(int i = 1; i <= n / i; i ++ ) {
        if(n % i == 0) {
            divi.push_back(i);
            if(n / i != i) divi.push_back(n / i);
        }
    }
    
    int ans = 1;
    for(auto t: divi) {//168
        bool ok = true;
        if(t == n) continue;
        else {
            vector<int> alls;
            for(int i = 1; i <= t; i ++ ) {
                int _gcd = -1;
                for(int j = i + t; j <= n; j += i ) {
                    if(_gcd == -1) _gcd = abs(a[j] - a[j - t]);
                    else _gcd = gcd(_gcd, abs(a[j] - a[j - t]));
                }
                alls.push_back(_gcd);
            }
            int _gcd = -1;
            for(auto t: alls) {
                if(_gcd == -1) _gcd = t;
                else _gcd = gcd(t, _gcd);
            }
            
            if(_gcd == 1) ok = false;
        }
        if(ok) ans ++;
    }
    cout << ans << "\n";
}

int main() {
    ll t;
    cin >> t;
    while(t -- ) solve();
    return 0;
}

codeforces round914div2 C array game

这道题是个tips题,注意到当k大于3时答案总是0,在遇到无从下手的题目时一定要试着去寻找一些特判情况,将答案简化

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll INF = 1e18;

void solve() {
    ll n, k;
    cin >> n >> k;
    vector<ll> a(n + 1);
    ll minv = INF;
    for(int i = 1; i <= n; i ++ ) {
        cin >> a[i];
        minv = min(minv, a[i]);
    }
    sort(a.begin() + 1, a.end());
    ll ans = INF;
    if(k > 2) {
        cout << "0\n";
        return;
    } else if(k == 1) {
        for(int i = 1; i <= n; i ++ ) {
            for(int j = 1; j <= n; j ++ ) {
                if(i == j) continue;
                ans = min(ans, abs(a[i] - a[j]));
            }
        }
    } else if(k == 2) {
        for(int i = 1; i <= n; i ++ ) {
            for(int j = i + 1; j <= n; j ++ ) {
                if(i == j) continue;
                ll del = a[j] - a[i];
                int l = 1, r = n;
                while(l < r) {
                    int mid = l + r >> 1;
                    if(a[mid] >= del) r = mid;//找到第一个大于等于del的数
                    else l = mid + 1;
                }
                ans = min(ans, abs(a[l] - del));
                ans = min(ans, abs(a[l - 1] - del));
            }
        }
    }
    cout << min(ans, minv) << "\n";
}

int main() {
    ll t;
    cin >> t;
    while(t -- ) solve();
    return 0;
}

D set to max

题目大意:给出两个数组,a,b,每次可以从a中任意选择一段区间,并且把区间中元素赋值成区间最大值,easy version和hard version的区别就在于数据范围,有经验的话会立刻明白这个数据范围的作用就是限制求区间最值时的方式,时间复杂度O(n^2)允许的话可以直接暴力求解,反之则可以用线段树维护。现在去思考如何解决这个问题:为了方便我们对数据进行处理,把目标区间取出来是必要的。现在考虑方案的可行性,下述区间的表述都是取出来的区间段,即对于一个区间段的任意l,r,满足b[l] = b[r]。如果a中该区间段最大值大于了该区间中b的值(设为x),那么直接判负,因为较大数值会覆盖较小的数值.。同样的如果想要赋值成x,就要保证a数组中存在x,并且在达到x之前没有比x更大的数。这样就结束了吗,上文中提到了,较大值会覆盖最小值,倘若在枚举到当前区间前维护的区间的x比该区间的x要大,并且恰好我这个区间所需要的值被覆盖掉了,那么会导致可行的方案被判否,因此要贪心的以x值较小的区间开始维护,并且在以后的维护中,如果在a中的x必须跨越先前已经维护过的区间,那么答案就会被判否(因为会将以前维护好的覆盖掉)

现在思路就明朗了,时间复杂度O(nlogn)整体可控

代码:
 

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int INF = 0x3f3f3f3f;

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 2), b(n + 1);
    for(int i = 1; i <= n; i ++ ) cin >> a[i];
    for(int i = 1; i <= n; i ++ ) cin >> b[i];
    map<int, int> ma;
    a[0] = a[n + 1] = INF;
    vector<int> L(n + 1), R(n + 1);
    for(int i = 1; i <= n; i ++ ) {
        if(ma[b[i]] == 0) L[i] = 0;
        else L[i] = ma[b[i]];
        ma[a[i]] = i;
    }
    
    ma.clear();
    for(int i = n; i >= 1; i -- ) {
        if(ma[b[i]] == 0) R[i] = n + 1;
        else R[i] = ma[b[i]];
        ma[a[i]] = i;
    }
    
    struct node {
        int l, r, val, tag;
        bool operator < (const node &W) {
            return val < W.val;
        }
    };
    
    vector<node> tr(n * 4 + 1);
    
    auto pushup = [&](int u) {
        tr[u].val = max(tr[u << 1].val, tr[u << 1 | 1].val);
    };
    
    function<void(int, int, int)> build = [&](int u, int l, int r) {
        tr[u].l = l, tr[u].r = r;
        if(l == r) return;
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
    };
    
    function<void(int, int)> insert = [&](int u, int pos) {
        if(tr[u].l == tr[u].r && tr[u].l == pos) tr[u].val = a[pos];
        else {
            int mid = tr[u].l + tr[u].r >> 1;
            if(mid >= pos) insert(u << 1, pos);
            if(mid < pos) insert(u << 1 | 1, pos);
            pushup(u);
        }
    };
    
    function<int(int, int, int)> query = [&](int u, int l, int r) {
        if(tr[u].l >= l && tr[u].r <= r) return tr[u].val;
        else {
            int res = 0;
            int mid = tr[u].l + tr[u].r >> 1;
            if(mid >= l) res = query(u << 1, l, r);
            if(mid < r) res = max(res, query(u << 1 | 1, l, r));
            return res;
        }
    };
    
    build(1, 1, n);
    for(int i = 1; i <= n; i ++ ) insert(1, i);
    
    vector<node> st(4 * n + 1);
    
    function<void(int, int, int)> build1 = [&](int u, int l, int r) {
        st[u].l = l, st[u].r = r;
        if(l == r) return;
        int mid = l + r >> 1;
        build1(u << 1, l, mid);
        build1(u << 1 | 1, mid + 1, r);
    };
    
    auto pushup1 = [&](int u) {
        st[u].val = st[u << 1].val | st[u << 1 | 1].val;    
    };
    
    auto pushdown = [&](int u) {
        st[u << 1].val |= st[u].tag;
        st[u << 1].tag |= st[u].tag;
        st[u << 1 | 1].val |= st[u].tag;
        st[u << 1 | 1].tag |= st[u].tag;
        st[u].tag = 0;
    };

    function<void(int, int, int)> insert1 = [&](int u, int l, int r) {
        if(st[u].l >= l && st[u].r <= r) {
            st[u].val = 1;
            st[u].tag = 1;
        } else {
            pushdown(u);
            int mid = st[u].l + st[u].r >> 1;
            if(mid >= l) insert1(u << 1, l, r);
            if(mid < r) insert1(u << 1 | 1, l, r);
            pushup1(u);
        }
    };
    
    function<int(int, int, int)> query1 = [&](int u, int l, int r) {
        if(st[u].l >= l && st[u].r <= r) return st[u].val;
        else {
            int res = 0;
            int mid = st[u].l + st[u].r >> 1;
            if(mid >= l) res = query1(u << 1, l, r);
            if(mid < r) res |= query1(u << 1 | 1, l, r);
            return res;
        }
    };
    
    build1(1, 1, n);
    vector<node> pos;
    int i = 1, j = 1;
    while(i <= n && j <= n) {
        while(j <= n && b[i] == b[j]) j ++;
        pos.push_back({i, j - 1, b[i]});
        i = j;
    }
    //cout << L[4] << " ";
    sort(pos.begin(), pos.end());
    for(int k = 0; k < pos.size(); k ++ ) {
        auto t = pos[k];
        int l = t.l, r = t.r, x = t.val;
        //cout << l << " " << r << " " << x << "\n";
        int max_val = query(1, l, r);
        if(max_val > x) {
            cout << "NO\n";
            return;
        }
        
        if(max_val == x) {
            insert1(1, l, r);
            continue;
        }
        
        bool ok1 = false;
        bool ok2 = false;
        if(a[L[l]] == x && !query1(1, L[l], l) && (query(1, L[l], l) == x)) ok1 = true;
        if(a[R[r]] == x && !query1(1, r, R[r]) && (query(1, r, R[r]) == x)) ok2 = true;
        if(!ok1 && !ok2) {
            cout << "NO\n";
            return;
        } else {
            /*for(int i = l; i <= r; i ++ ) insert1(1, i);*/
            insert1(1, l, r);
        }
    }
    //cout << query1(1, 1, 2) << " ";
    cout << "YES\n";
}

int main() {
    int t;
    cin >> t;
    while(t -- ) solve();
    return 0;
}

codeforces round 932 div2 C find a mine

这是一道交互题,这道题这道题启示我到一个点的曼哈顿距离相等的所有点的路径是个菱形(如果没有超过图的边界的话)

D1. XOR Break — Solo Version

题目大意:对于x我们可以将x设为y或者xXORy并且满足y < x并且xXory < x问是否可以将x变成m(m < x)

数据范围很大,并且有xor操作,直接考虑拆位

现在似乎仍然无从下手,那么试着挖掘一些隐含在题目中的性质

m小于x试着考虑一下这个条件的性质:

容易得到,如果xy满足小于关系那么有

x: same 1 ??????

m:same 0 ??????

从高位起第一位不同的二进制表示,x为1,m为0

再考虑如果x Xor y < x要满足什么条件

x:             same 1 ??????

y          :  00000 1 ??????

m         :  same   0 ??????(x xor y = m)

其实这里可以注意到如果same存在1的话,那么后面的????填什么都可以因为y肯定比x小并且m本来就比x小,现在要讨论的情况就是same全为0的情况。如果m的?号位为0的话,那么x和y的?号位要相同,不是0就是1,反之?号位不同,也就是说,如果在same 1以后的二进制表示位中,如果m中出现的第一个1对应的x中二进制中表示位是1的话,那么我们同样可以将x转化为m,反之就证明当前的y比x要小,不满足题意,这时候我们要考虑是否可以借助一个中间值转化一下,使得这一位的值变成1(借位),借位只能向1借,并且不能same后面的那位1实际上是不能动的,这里可以手动模拟一下,也就是说,如果在same1后面的二进制位到该位之间x二进制表示位为1的话,我们就可以借助这个中间值将其转化为上述的情况。(可以找个较小的数值模拟一下)

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

void solve() {
    ll n, m;
    cin >> n >> m;
    bool ok = 0;
    ll pos = -1;
    for(ll i = 62; i >= 0; i -- ) {
        if(n >> i & 1) {
            if(!(m >> i & 1)) {
                pos = i;
                break;
            }
        }
        
        if(n >> i & 1) ok = true;
    }
    //cout << pos << "LL";
    if(ok) {
        cout << "1\n";
        cout << n << " " << m << "\n";
    } else {
        bool flag = false;
        for(ll i = pos - 1; i >= 0; i -- ) {
            if(m >> i & 1) {
                if(n >> i & 1) {
                    flag = true;
                    break;
                }
                
                if(!(n >> i & 1)) break;
            }
        }
        
        if(flag) {
            cout << "1\n";
            cout << n << " " << m << "\n";
        } else {/*
            0 0 0 0 0 1 a b c 0
            0 0 0 0 0 1 a b c 1
            0 0 0 0 0 0 0 0 0 1
        */
            ll pos1 = -1;
            for(ll i = pos - 1; i >= 0; i -- ) {
                if(m >> i & 1) break;
                if(n >> i & 1) {
                    pos1 = i;
                    break;
                }
            }
            
            if(pos1 == -1) cout << "-1\n";
            else {
                cout << "2\n";
                ll res = n;
                ll now = 1ll << pos;
                for(ll i = 62; i >= pos; i -- ) {
                    res -= (n >> i & 1) * (1ll << i);
                }
                
                for(ll i = pos1 - 1; i >= 0; i -- ) {
                    if((m >> i & 1) && !(n >> i & 1)) {
                        res += 1ll << i;
                        break;
                    }
                }
                cout << n << " " << res << " " << m << "\n";
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    ll t;
    cin >> t;
    while(t -- ) solve();
    return 0;
}

codeforces round 991 div3 G

题目大意,从一颗树中删除一条链,找到删除后联通块数量的最大值

树类的问题,直接考虑dfs,树形dp

首先有一个很重要的性质,路径一定要尽可能多的删(除了叶子节点),并且每个点的贡献与这个点的临边数量有关,其实思考一下就是树的直径,只不过把边权换成了点权...

这里说一下树的直径:

代码:
 

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

void solve() {
    int n;
    cin >> n;
    vector<vector<int>> adj(n + 1);
    for(int i = 2; i <= n; i ++ ) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    
    vector<int> dp(n + 1);
    int ans = 0;
    function<void(int, int)> dfs = [&](int u, int fa) {
        int tot = adj[u].size();
        dp[u] = max(0, tot - 2);
        int fir = -1, sec = -1;
        bool flag = true;
        for(auto t: adj[u]) {
            if(t == fa) continue;
            flag = false;
            dfs(t, u);
            dp[u] = max(dp[u], tot - 2 + dp[t]);
            if(dp[t] >= fir) {
                sec = fir;
                fir = dp[t];
            } else if(dp[t] >= sec) {
                sec = dp[t];
            }
            
            int res = max(0, fir) + max(0, sec);
            if(tot == 1) res ++;
            else if(tot > 2) res += tot - 2;
            ans = max(res, ans);
        }
        if(flag) dp[u] = 1;
    };
    
    if(n == 2) cout << "1\n";
    else {
        dfs(1, 1);
        cout << ans << "\n";
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while(t -- ) solve();
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2260420.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(四)

《拉依达的嵌入式\驱动面试宝典》—C/CPP基础篇(四) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《拉…

又细又长的马尾:tail

英语里边有一个单词 tail&#xff0c;意为“尾巴”&#xff0c;这应当是众所周知的事情了。 不过&#xff0c;tail 这条尾巴&#xff0c;并不简单&#xff0c;因为它还是一个词根&#xff0c;也就是说 tail 其实是自由词素。 事实上&#xff0c;tail 最初来自 马尾 这样一个概…

Lumos学习王佩丰Excel第二十一讲:经典Excel动态图表实现原理

一、动态图表实现原理 1、理解图表中的数据系列 在Excel图表中&#xff0c;系列指的是图表中的数据集合&#xff0c;它通常代表着一个数据源。每个系列都可以包含多个数据点&#xff0c;这些数据点在图表中以特定的形式展现&#xff0c;如柱状图中的柱子&#xff0c;折线图中…

使用Qt Creator设计可视化窗体(一)

一、创建项目 打开 Qt Creator &#xff0c;在菜单栏中选中&#xff1a; “文件” --------> “新建文件或项目” &#xff1b;或者使用快捷键&#xff1a;Ctrl n&#xff1b;或者直接点击&#xff1a;“new” Qt 中的构建工具有三种可供选择&#xff0c;分别是&#…

Rust之抽空学习系列(四)—— 编程通用概念(下)

Rust之抽空学习系列&#xff08;四&#xff09;—— 编程通用概念&#xff08;下&#xff09; 1、函数 函数用来对功能逻辑进行封装&#xff0c;能够增强复用、提高代码的可读 以下是函数的主要组成部分&#xff1a; 名称参数返回类型函数体 1.1、函数名称 在Rust中&…

springboot423玩具租赁系统boot(论文+源码)_kaic

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装玩具租赁系统软件来发挥其高效地信息处理的作用&#xff0c…

.NET6 WebAPI从基础到进阶--朝夕教育

1、环境准备 1. Visual Studio 2022 2. .NET6 平台支持 3. Internet Information Services 服务器&#xff08; IIS &#xff09; 4. Linux 服务器 【 CentOS 系统】 ( 跨平台部署使用 ) 5. Linux 服务器下的 Docker 容器&#xff08; Docker 部署使用&#xff09; …

Attentive Fusion论文精读

OPV2V: An Open Benchmark Dataset and Fusion Pipeline for Perception with Vehicle-to-Vehicle Communication 文章目录 背景创新点1.提出新的数据2.提出了一种注意力中间融合管道 2.相关工作车对车感知早期融合晚期融合中间融合 车对车数据集 3. OPV2V 数据集A.数据收集模…

Datawhale AI冬令营(第一期)task2--微调玩法攻略

目录 1.微调玩法攻略 1.1.微调思路 1.2.什么是大模型人格化&#xff1f; 1.3. 大模型人格化的应用场景 1.4 构建对应格式的数据集 1.4.1 选择数据格式 1.4.2 Alpaca 格式要求 1.4.3 构建数据集 1.4.4 没有剧本怎么办 1.4.5 整理成 json 格式 1.微调玩法攻略 1.1.微…

VQ-VAE和VAE 的区别是什么?

第一行所展示的就是普通的VAE,它的核心是通过encoder和decoder&#xff0c;将像素空间的图像压缩到一个提取了核心特征的隐变量向量。VQ-VAE的思想是&#xff0c;即使VAE中压缩的这个隐变量中的向量提取了图片中的核心特征信息&#xff0c;但是这些信息仍然可能存在冗余&#x…

Redis--高并发分布式结构

目录 一、引言 二、redis 1.什么是redis&#xff1f; 三、基础概念 1.什么是分布式&#xff1f; 2.应用服务和数据库服务分离 3.负载均衡 4.分库分表 5.微服务架构 四、总结 一、引言 本篇文章就简单介绍一下什么是redis&#xff0c;以及一些关于高并发和分布式结构的…

188-下翻便携式6U CPCI工控机箱

一、板卡概述 下翻式CPCI便携工控机,系统采用6u cpci背板结构,1个系统槽,7个扩展槽, 满足对携带的需求,可装标准6U8槽CPCI主板,8个扩展槽, 满足客户对空间扩展的需求.可宽温服务的工作产品,15高亮度液晶显示屏,超薄88键笔记本键盘,触摸式鼠标,加固型机箱结构,使它能够适应各种复…

Linux 磁盘满了怎么办?快速排查和清理方法

当 Linux 磁盘满了&#xff0c;会导致系统无法正常运行&#xff0c;比如无法写入文件、服务停止、甚至系统崩溃。因此&#xff0c;快速排查并清理磁盘空间是非常重要的。以下是详细的排查和解决步骤&#xff1a; 一、快速定位磁盘占用原因 1. 检查磁盘使用情况 使用 df 命令查…

OpenGL ES详解——多个纹理实现混叠显示

目录 一、获取图片纹理数据 二、着色器编写 1. 顶点着色器 2. 片元着色器 三、绑定和绘制纹理 1. 绑定纹理 2. 绘制纹理 四、源码下载 一、获取图片纹理数据 获取图片纹理数据代码如下&#xff1a; //获取图片1纹理数据 mTextureId loadTexture(mContext, R.mipmap.…

对话小系统(智能图书助手)

对话小系统&#xff08;智能图书助手&#xff09; 文章说明核心代码效果展示源码下载 文章说明 现在GPT的功能十分强大&#xff0c;是否可以利用开源的接口来实现自己的智能小助手呢&#xff0c;我想到可以提供一些能力接口&#xff0c;然后对问询内容进行意图识别&#xff0c;…

微服务-01

1.认识微服务 1.1 单体架构 单体架构&#xff08;monolithic structure&#xff09;&#xff1a;顾名思义&#xff0c;整个项目中所有功能模块都在一个工程中开发&#xff1b;项目部署时需要对所有模块一起编译、打包&#xff1b;项目的架构设计、开发模式都非常简单。 当项目…

WebView2教程(基于C++)【一】环境初始化

创建一个VisualStudio C项目&#xff0c;通过NuGet包管理器安装两个包&#xff1a; 注意&#xff0c;在项目属性页设置项目使用&#xff1a;C 20&#xff0c;子系统设置成窗口&#xff08;相应的预处理器也要改变&#xff09;&#xff0c;DPI识别设置成每个监视器高DPI识别。 …

KMP算法图解解析(C语言)

文章目录 一.引言二.KMP算法解析三.代码实现1.对目标子串的处理&#xff08;创建next数组&#xff09;二.寻找子串的KMP算法实现 一.引言 kmp算法是由三位大牛共同研究提出的&#xff0c;全称为Knuth-Morris-Pratt算法&#xff0c;简写为KMP算法。 kmp算法用来解决子串的问题&a…

数据冒险、控制冒险、结构冒险

计算机组成原理 数据冒险、控制冒险、结构冒险 对所有用户&#xff08;所有程序员&#xff09;可见&#xff1a;PSW、PC、通用寄存器 PSW&#xff08;条件转移需要用到&#xff0c;程序员使用CMP指令的时候也需要用到所以是对用户可见&#xff09;PC&#xff08;跳转指令需要…

Python机器学习笔记(七、深度学习-神经网络)

深度学习算法经过精确调整&#xff0c;只适用于特定的使用场景。先学习较为简单的深度学习算法&#xff0c;用于分类和回归的多层感知机&#xff08;multilayer perceptron&#xff0c;MLP&#xff09;&#xff0c;它可以作为研究更复杂的深度学习方法的起点。MLP 也被称为&…