The 2024 ICPC Asia Nanjing Regional Contest(2024南京区域赛EJKBG)

2024南京icpc区域赛详解与难点解释 阅读详情
AI摘要

本文详细分析了2024 ICPC亚洲南京区域赛的几道编程题,包括Left Shifting 3、Social Media、Strips、Birthday Gift和Binary Tree。每道题均涉及不同的算法思想,如模拟、贪心、思维题及树的重心等,提供了详细的解题思路与时间复杂度分析。

E. Left Shifting 3

分析:签到模拟,破环成链。

#include <bits/stdc++.h>

using namespace std;

void solve()
{
    int n, k;
    cin >> n >> k;
    vector<char> s(n * 2 + 1);
    for (int i = 0; i < n; i++)
        cin >> s[i];
    k = min(n, k);
    for (int i = n; i <= n + k - 1; i++)
    {
        s[i] = s[i - n];
    }
    vector<int> a(n * 2 + 1, 0), snum(n * 2 + 1, 0);
    for (int i = 0; i <= n + k - 1 - 5; i++)
    {
        if (s[i] == 'n' && s[i + 1] == 'a' && s[i + 2] == 'n' && s[i + 3] == 'j' && s[i + 4] == 'i' && s[i + 5] == 'n' && s[i + 6] == 'g')
        {
            a[i + 6] = 1;
        }
    }
    for (int i = 1; i <= n + k; i ++){
        snum[i] = snum[i-1] + a[i-1];
    }

    int mx = 0;
    for (int i = 1; i + n - 1 <= n + k; i++)
    {
        int j = i + n - 1;        
        mx = max(mx, snum[j] - snum[i - 1]);
    }
    cout << mx  << endl;
}

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

J. Social Media

分析:分类讨论。

case1 :  找到一个和当前点有连接的两个点 可以直接计算复杂度等于边数*2

 case2 : 或者找两个不相连但是和联通块的连接很大的 这个时候直接找两个就可以复杂度等于点数

时间复杂度是:O(NlogN)+O(MlogN)+O(MlogM)+O(K)

#include <bits/stdc++.h>
using namespace std;
const int N = 200010;

void solve()
{
    int n, m, k;
    cin >> n >> m >> k;
    vector<vector<int>> adj(k + 1);
    vector<int> value(k + 1);   // 记录了如果选这个人可以创造的价值(就是这个人和原来几个人的互评数)
    set<int> st;
    for (int i = 0; i < n; i++)
    {
        int x;
        cin >> x;
        st.insert(x); // 标记最初的几个人是谁 不能选这几个人
    }
    int ans = 0;
    for (int i = 0; i < m; i++)
    {
        // 边的个数
        int u, v;
        cin >> u >> v;
        if(u != v){
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
        if(st.count(u) && st.count(v))
            ans++;
        else if(st.count(u) && !st.count(v)){  
            value[v] ++ ; 
        }else if(!st.count(u) && st.count(v)){
            value[u]++;
        }else{
            if( u == v)  // 注意考虑自己给自己评论创造的价值
                value[u]++;
        }
    }
    // 枚举可能选择的点
    int tmp = ans;
    for(int i = 1; i <= k ; i ++){
        if(!st.count(i)){
            int t_ans = tmp;
    // case1 :  找到一个和当前点有连接的两个点 可以直接计算复杂度等于边数*2
            map<int , int>mp;
            for(auto v : adj[i])
                mp[v]++;
            for (auto p : mp)
                if(!st.count(p.first)){
                    ans = max(ans, t_ans + p.second + value[p.first] + value[i]);
                }   
        }
    }
    // case2 : 或者找两个不相连但是和联通块的连接很大的 这个时候直接找两个就可以复杂度等于点数
    int mx1 = 0, mx2 = 0, d = 0;
    for (int i = 1; i<= k ; i ++){
        if(!st.count(i)){
            if(value[i] > mx1){
                mx2 = mx1 ;
                mx1 = value[i];
            }else if(value[i] > mx2){
                mx2 = value[i];
            }
        }
    }
    ans = max(tmp + mx1 + mx2, ans);
    // 看最多的两个有没有发消息 或者看发了多少消息
    cout << ans << endl;
}

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

K. Strips

分析:反悔贪心。

我们尽可能的对于遍历到的每一个需要覆盖的点,都从这个点开始覆盖,这样可以尽可能少用条带,如果发现覆盖之后会覆盖不该覆盖的就把这个条带左移,我们已经记录了前面的条带的起始和终止的位置。

Case一:如果当前的条带和上一个条带中间是有不能覆盖的格子的。

        则当前的条带最多能移动到这些不能覆盖的格子中的最右侧的格子的右侧,看是否能满足需要移动的间隔,如果能满足则移动并break去处理下一个需要覆盖的格子,不能满足则-1。

Case一:如果当前的条带和上一个条带中间是没有不能覆盖的格子。

        case1:如果和前面的条带有足够的间隔去移动就直接移动即可,并break去处理下一个需要覆盖的格子。

        case2:如果没有足够的间隔去移动就把这两个相邻的条带合并成一个大的条带再去移动,为了方便要记录此时可以移动的间隔,直到sum(可以移动的间隔)>= 需要移动的间隔break,重复上面的过程。

复杂度就是是 O(n log n + m log m + n log m)的。

#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define PII pair<int ,int> 
vector<PII> v;
void solve(){
    int n , m , k , w;
    cin >> n >> m >> k >> w;
    vector<int>a(n) , b(m + 2);
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 1; i <= m; i++){
        cin >> b[i];
    }
    b[0] = 0, b[m + 1] = w + 1;           // 易错点1 
    sort(a.begin(), a.end());
    sort(b.begin(), b.end());
    vector<PII> seg;                      // 存已经相连的覆盖的线段
    seg.push_back({0, 0});
    for (int i = 0; i < n; i++){
        // 看最后相连的线段满不满足要求
        if (seg.back().y >= a[i])
            continue;
        //不可以的话就需要开一个线段
        seg.push_back({a[i], a[i] + k - 1}); 
        // 看右边第一个临界的状态是哪个
        int posr = lower_bound(b.begin(), b.end(), a[i]) - b.begin();
        int rbr = b[posr];
        if (seg.back().y < rbr) // 没有产生影响 否则的话就需要左移
            continue; 
        int nd_move = seg.back().y - rbr + 1; // 需要移动的间隔
        while(1){
            // 看和前一个段中间的空隙
            int posl = lower_bound(b.begin(), b.end(), seg[seg.size() - 2].y) - b.begin(); //找到临界的rbl的位置
            int rbl = b[posl];
            if(rbl == rbr){
                // 说明是一个东西就不用但心
                int ok_move = seg.back().x - seg[seg.size() - 2].y - 1; // 最多可以移动的间隔
                if(ok_move >= nd_move){
                    // 可以移动的话就直接移动然后break
                    seg.back().y -= nd_move;
                    seg.back().x -= nd_move;
                    break;
                }else{
                    //可以合并成一个大的段继续判断 不可以直接达成目标就尽可能先和前一个段合并
                    //再去看这个合成的段和前一个段能不能达成目标
                    if(seg.size() >= 3){    
                        // 易错点2 因为如果剩余段是3 还是可以合并最后两段 再去判断一次 
                        //  当剩余段是2的时候 就需要直接退出了 因为合并成一段之后无法继续
                        nd_move -= ok_move;
                        int cur_len = seg.back().y - seg.back().x + 1; //长度
                        seg.pop_back();
                        seg.back().y += cur_len;
                    }else{
                        // 段数<=2合并不了就退出
                        cout << -1 << endl;
                        return;
                    }
                }
            }else{
            // 和前一个段被控制的不是同一个黑色的块 依旧可以尝试移动到最最左边的黑块的右边
                int black_r = lower_bound(b.begin() , b.end() , seg.back().x) - b.begin() - 1;
                int ok_move = seg.back().x - b[black_r] - 1; 
                if( ok_move >= nd_move){
                    //代表可以移动
                    seg.back().x -= nd_move;
                    seg.back().y -= nd_move;
                    break;
                }else{
                    cout << -1 <<endl;
                    return;
                }
            }
        }
    }
    //  然后找到所有可以移动的段
    int len = 0;
    vector<PII> ans;
    for (auto p : seg)
    {
        if(p.y ==0 && p.x == 0 )   // 易错点3
            continue;
        len += (p.y - p.x + 1);
        ans.push_back({p.x, (p.y - p.x + 1) / k}); // 起点和数量
    }
    cout << len / k << endl; // 肯定是k的倍数
    for (auto p : ans)
    {
        for (int i = 0; i < p.y; i++)
        {
            cout << p.x + i * k << " ";
        }
    }
    cout << endl;
}

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

B. Birthday Gift

分析:这个题就是纯纯的思维题了,知道结论或者方法的话非常简答,不知道的话就很牢。

我们发现奇数位置的两个0是无论如何是不能抵消的,所以抵消的一定是奇数和偶数位置的相同数,所以我们去记录偶数位置的0 1 2的数量,以及奇数位置的 0 1 2 数量,注意偶数位置把0统计成1 , 把1统计成0(可以想象偶数位置都翻转,只有统计过后的数字不相同才可以抵消) , 这样最后不考虑2得到的结果就是max(cnt1 , cnt0) - min(cnt1 , cnt0),无论如何最后的结果一定全是1或者全是0,这个时候把2考虑进去,尽可能转换成小的,可以把上面的式子尽可能小所以最后的答案就是:ans =  max(cnt1 , cnt0) - min(cnt1 , cnt0) - cnt2。

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define ll long long

void solve()
{
    string s;
    cin >> s;
    int n = s.size();
    int cnt0 = 0, cnt1 = 0, cnt2 = 0;
    // 统计偶数位置翻转后的情况 2 不用管
    for(int i = 0 ; i< s.size() ; i ++){
        if(i % 2 == 1){
            // 这就是偶数位置
            if(s[i] == '0') cnt1 ++;
            else if(s[i] == '1') cnt0 ++;
            else
                cnt2++;
        }else{
            if (s[i] == '0')
                cnt0++;
            else if (s[i] == '1')
                cnt1++;
            else
                cnt2++;
        }
    }
    int ans =  max(cnt1 , cnt0) - min(cnt1 , cnt0) - cnt2;
    if(ans < 0 ){
        if(abs(ans) % 2)
            cout << 1 << endl;
        else
            cout << 0 << endl;
    }else{
        cout << ans << endl;
    }
}

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

G. Binary Tree

分析:收获颇多的一个交互题,要理解树的重心。

题目让我们找到一个隐藏点,每次可以询问两个点到这个隐藏点谁的距离更近,让我们不超过log(n)的次数,我们如果学习过树的重心就可以知道,树的重心的最大的子树的大小是<=总的节点数量/2的,如果我们每次询问都从树的重心出发会不会每次把需要考虑的点数减少一半呢?

寻找树重心的模板代码,要非常熟悉。

        vector<int> mss(n + 1), siz(n + 1);
        auto dfs = [&](auto &&dfs, int u, int fa) -> void  //dfs出所有每个点作为根的树的大小 以及 每个点向下的子树的最大子树
        {
            siz[u] = 1;
            for(auto v : adj[u]){
                if(v == fa)
                    continue;
                dfs(dfs , v , u);
                siz[u] += siz[v];
                mss[u] = max(mss[u], siz[v]);
            }
        };
        dfs(dfs, s, -1);
        int tot = siz[s] , rt;
        for (int i = 1; i <= n; i++){
            mss[i] = max(mss[i], tot - siz[i]); // tot-siz[i] 是父亲节点方向的子树大小
            if(siz[i] && mss[i] <= tot/ 2){     // 注意不能选择被剪掉的 所以要保证siz[i]>0
                rt = i; //这就是重心
            }
        }

假设我们已经找到了树的重心是rt。

case1:如果此时和rt相连的边数是0,那就理所当然的直接输出rt了。

case2:如果和rt相连的边数是1,那么我们询问rt和这个相连的点。

        if(询问结果是0)就代表rt离隐藏点更近,显然直接输出rt即可。

        else 代表隐藏点在这个相连的点或它的子树中

case3:如果和rt相连的边数是2,那么我们就直接询问这两个点,为什么不询问rt和其中的一个点呢,答案是效率较低,我们直接询问这两个点,(可以思考一下询问根是不是数据规模不一定小1/2)

        if(1) 就代表隐藏点就是rt,if(2) or if(0) 就代表是其中一个点或它的子树中,点数的规模一定会减少1/2以上的。

case4:如果和rt相连的边数是3,其实这种情况和上一种情况是类似的,我们想要找到数据规模缩小一半的询问,就会发现询问根是做不到的,如果询问和根相连的最大的两个子树,就恰好可以满足我们的要求。

        if(1)就代表隐藏点是rt或是那个最小的子树,if(2) or if(0)隐藏点就分别一定在最大的两个子树和与rt相连的两个点上,数据规模一定会缩小一半以上,太神奇拉~

根据询问的结果去修剪不需要考虑的子树。

            if(d == 0 ){
                s = u ;
                adj[s].erase(find(adj[s].begin(), adj[s].end(), rt));
            }else if(d == 2){
                s = v;
                adj[s].erase(find(adj[s].begin(), adj[s].end(), rt));
            }else{ // 
                s = rt;
                adj[s].erase(find(adj[s].begin(), adj[s].end(), u));
                adj[s].erase(find(adj[s].begin(), adj[s].end(), v));
            }

然后重复上述过程,最多不超过log2(n)次。

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

void solve()
{
    int n;
    cin >> n;
    vector<vector<int>> adj(n + 1);
    for(int i = 1 ; i <= n ; i ++){
        int u, v;
        cin >> u >> v;
        if( u != 0 )
            adj[i].push_back(u), adj[u].push_back(i);
        if(v != 0)
            adj[i].push_back(v), adj[v].push_back(i);
    }
    
    auto ask = [&](int u, int v)->int{
        cout << "? " << u << " " << v << endl;
        int x;
        cin >> x;
        return x;
    };

    auto answer = [&](int x) -> void
    {
        cout << "! " << x << endl;
    };
    int s = 1;
    while(1){
        vector<int> mss(n + 1), siz(n + 1);
        auto dfs = [&](auto &&dfs, int u, int fa) -> void  //dfs出所有每个点作为根的树的大小 以及 每个点向下的子树的最大子树
        {
            siz[u] = 1;
            for(auto v : adj[u]){
                if(v == fa)
                    continue;
                dfs(dfs , v , u);
                siz[u] += siz[v];
                mss[u] = max(mss[u], siz[v]);
            }
        };
        dfs(dfs, s, -1);
        int tot = siz[s] , rt;
        for (int i = 1; i <= n; i++){
            mss[i] = max(mss[i], tot - siz[i]); // tot-siz[i] 是父亲节点方向的子树大小
            if(siz[i] && mss[i] <= tot/ 2){     // 注意不能选择被剪掉的 所以要保证siz[i]>0
                rt = i; //这就是重心
            }
        }
        if(adj[rt].size() == 0){ 
            answer(rt);
            return;
        }else if(adj[rt].size() == 1){
            int v = adj[rt][0];
            int d = ask(rt, v);
            if(d == 0){
                answer(rt);
                return;
            }else{
                answer(v);
                return;
            }
        }else
        { // adj[rt].size() == 2 和 adj[rt].size() == 3 的处理方法是相通的 所以可以只写一遍
            sort(adj[rt].begin(), adj[rt].end(), [&](auto lx, auto ly)
                 { return siz[lx] > siz[ly]; });
            int u = adj[rt][0] , v =adj[rt][1];
            int d = ask(u, v);
            if(d == 0 ){
                s = u ;
                adj[s].erase(find(adj[s].begin(), adj[s].end(), rt));
            }else if(d == 2){
                s = v;
                adj[s].erase(find(adj[s].begin(), adj[s].end(), rt));
            }else{ // 
                s = rt;
                adj[s].erase(find(adj[s].begin(), adj[s].end(), u));
                adj[s].erase(find(adj[s].begin(), adj[s].end(), v));
            }
        }
    }
}
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}

【白话系列】倍增算法 【序言】         我认为吧,所有能够优化复杂度的算法都是神奇的,所有能够化繁琐为形象的文字都是伟大的。一直觉得倍增算法是个很神奇的东西,所以决定写点东西纪念一下它。但是作为一个非常不称职的OIER,我非常讨厌在看别人的算法解析时整版的i,j,k等我看到鼠标就惯性移到右上角的符号语言,所以我想用最形象的方式来纪念它。 【一】         从前,有一只可爱得不得了的小白兔,它想从 阅读详情

相关推荐

app编写需要哪种语言

原生App开发:优选Swift(iOS)和Kotlin(Android)。跨平台App开发:优选Flutter(Dart)和React Native(JavaScript)。游戏App开发:优选Unity(C#)和Unreal Engine(C++)。低代码工具:适合简单、快速的App制作。

fanying_98的博客 2071

2024ICPC南京站题解

2024ICPC南京站

weixin_73725403的博客 4175

mfcc总结,这个mel三角滤波器分组到底是如何起作用的呢?

先看fft频谱图(这是4096字节取样fft计算,横轴频率是从0到512,后边意义不大,未取,纵轴是振幅),那些我随便画的蓝色线,你有什么联想?: 再看,这绿色线,是否有一种上升后,便逐渐式微的感觉,都是三角形的,这或许也是mel当初和绝大多数人看到的: 如果在振幅上加上一条限制的黑线(振幅门槛限制),黑色线以下很多频率就没有意义了,你看,有用的频率连一半(512/2=256)都占不到...

ganggangwawa的博客 9908

2024ICPC南京站游记

其实也没啥好总结的,最大的收获大概是打破了多年以来线下不超过6题的超级debuff,以及重新找回了对南京这座城市的好感/xk本来想把这篇当成算法竞赛生涯最后的回忆录,但是鉴于这次打得还行或许会厚着脸皮再要一个ecf名额吧,如果有的话那就强行再续两个月的在役时间,回忆录什么的到时候再说吧qwq。

liuzhangfeiabc的博客 1619

32位MIPS流水线CPU设计

32位MIPS流水线CPU设计(vivado)

m0_51320209的博客 3202

保姆级教程:用中移ML307模组对接高德/OneOS定位服务,从配置apikey到解析+MLBSLOC状态码

本文详细介绍了如何使用中移ML307系列模组对接高德/OneOS定位服务,从配置apikey到解析+MLBSLOC状态码的全过程。涵盖高德定位服务和OneOS定位服务的配置步骤、常见错误处理及性能优化技巧,帮助开发者快速实现基站定位功能,提升物联网项目的定位精度和稳定性。

weixin_30632089的博客 508

2024 ICPC 国际大学生程序设计竞赛 亚洲区域赛(南京站)- M. Ordainer of Inexorable Judgment

本文研究了一个关于射线与凸多边形接触时间的几何问题。题目描述了一条从原点发出的射线以恒定角速度旋转,并给出了射线实际覆盖范围,给定一个凸多边形和总时间t,要求计算射线与多边形接触的总时间。

joker822519866的博客 1282

【RT-DETR涨点改进】全网独家创新、细节涨点改进篇 | AAAI 2025 | 将 CEM 颜色增强模块引入RT-DETR ,目标检测不再惧怕雾天和低光检测、小目标检测、遥感目标检测高效涨点

本文提出了一种新型结构引导去雾网络(SGDN),通过双色引导桥(BGB)和色彩增强模块(CEM)有效解决雾霾图像去雾问题。BGB利用YCbCr空间的纹理特征引导RGB特征恢复,CEM通过聚合YCbCr通道信息增强RGB色彩感知。实验证明该方法在真实雾霾数据集上优于现有技术,能同时保持色彩准确性和纹理清晰度。文章还提供了完整的代码实现和模型配置指南,包括三种改进版RT-DETR网络结构(rtdetr-l/r18/r50-CEM.yaml),为图像去雾和目标检测任务提供了实用解决方案。

Ai缝合怪、助力小伙伴高效发论文 351

2024icpc南京

本文总结了五道编程竞赛题目及解题思路:1. E.LeftShifting3:通过字符串循环移位匹配"nanjing",优化KMP算法,考虑移动次数限制;2. J.SocialMedia:建模朋友圈消息传播,分类讨论朋友间互动情况,寻找最大可见消息数;3. K.Strips:在细胞序列中合理放置地毯覆盖红色细胞,避免黑色细胞,采用区间分割策略;4. B.BirthdayGift:通过字符变换和删除操作,将问题转化为统计字符出现次数的数学关系;5. G.BinaryTree:交互题,利用树的

2401_87287398的博客 1059

【Bug已解决】Claude Team Plan 购买席位报错 Payment failed 解决方案

方案适用场景推荐指数检查账单历史状态排查的第一步⭐⭐⭐⭐⭐更换支付方式类型快速尝试是否能绕开问题⭐⭐⭐联系官方支持团队最终解决问题的正规渠道⭐⭐⭐⭐⭐临时过渡方案紧急用人需求的应急处理⭐⭐⭐关注官方修复进度确认属于系统性缺陷的场景⭐⭐⭐⭐Claude Team Plan 增购席位报的问题,社区反馈和实际排查表明很大概率属于平台计费系统在处理按比例分摊费用这类复杂计算链路时的系统性缺陷,而不是用户自身的支付信息填写有误。先排除自身账单历史是否存在异常。

一键难忘的博客 4183

YOLOv11改进 | 模型知识蒸馏篇 | 利用模型蒸馏改进YOLOv11进行无损涨点 | CWDLoss(在线蒸馏 + 离线蒸馏)

这篇文章给大家带来最新改进的是模型的蒸馏利用教师模型指导学生模型从而进行模型的涨点,本文的内容不仅可以用于论文中,在目前的绝大多数的工作中模型蒸馏是一项非常重要的技术,所以大家可以仔细学习一下本文的内容,本文从YOLOv11的项目文件为例,进行详细的修改教程,文章内包括完整的修改教程,针对小白我出了视频修改教程,如果你还不会我提供了修改后的文件大家直接运行即可,所以说不用担心不会适用!模型蒸馏真正的无损涨点,蒸馏你只看这一篇文章就足够了!欢迎大家订阅我的专栏一起学习YOLO!

Snu77的博客 3310

2024南京ICPC J. Social Media(直观命名+详细注释版)

也就是说不一定是取 两个相互间评论特别多的非好友人 , 也可能取两个相互间没什么评论,但与已有好友间评论很多的人。如果两人间评论很多,与已有好友间评论也多,这种情况可以 盖住 上面的情况,分开取最后再去最大值即可。可能会出现有 非好友人 与 已有好友 间评论非常多,但与 其他非好友人 之间的评论很少的情况。题目设定最多再加两个好友,显然的,要看到更多的评论,就要加更多的好友,所以加两个。题目设定与微信朋友圈相同。

qq_39804992的博客 730

大数据在电力行业的应用案例解析 -【电力技术】(十)电力数字化运营与大数据精准服务体系建设

电力数字化运营,是大数据在电力行业从技术场景走向业务价值的最终落点。它以数据为纽带,将用户、设备、服务、收益、风险全部纳入统一闭环,实现从 “管好电” 向 “运营好能源资产” 升级。在新型电力系统与市场化改革双重驱动下,谁能用好数据、建好闭环、做好运营,谁就能在服务、成本、效益、安全上建立长期优势。

getusushu的博客 69

2023icpc南京站

2023icpc南京站 C. Primitive Root F. Equivalent Rewriting G. Knapsack I. Counter

鱼香rose_的博客 2180

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Binary Tree(2024 ICPC 南京站)

Binary Tree(2024 ICPC 南京站)Given a binary tree with n vertices, your task is to find a special vertex s in the tree with at most p = llog2 n」queries. That is to say, p is the largest integer such that 2p ≤ n. Each query consists of two different vertices u

BoBoo文睡不醒 1327

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

2024南京ICPC K.Strips(直观命名+详细注释版)

w的范围给的1e9 , 一开始没注意到 , 以为是1e5 , 所以不能用数组来模拟格子的情况 , 有下标还是要优先考虑用下标。处理完之后 , 若第一个条带压到的开头的黑块 , 则该区间没有合法放置条带的方法 , 则整体也没有合法放置条带的方法。每个区间中 , 先不考虑黑块的存在 , 用贪心的思想 , 用红块的位置作为条带的左端 , 将条带的左端位置储存起来。在一条格块中 , 已知 所有红块的位置 , 所有黑块的位置 , 条带的长度 , 总块数。首前尾后加一个黑块 , 每两个黑块之间作为一个小区间来处理。

qq_39804992的博客 920

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

ICPC 2023 区域赛南京站题解 + 重现赛游记

本文分享了洛谷重现赛的经历和部分题解。作者团队(He_XY、UKBwyx等)在比赛中获得第三名,并详细讲解了8道题目,代码简洁高效,适用于大范围数据。

AKDreamer_HeXY的博客 802

The 2023 ICPC Asia Nanjing Regional Contest (The 2nd Universal Cup. Stage 11: Nanjing)

容易发现f【i+1】>=f【i】,g【i】>=g【i+1】,有单调性,可以发现一定存在位置p,使得1到p min(f【i】,g【i】)取f【i】,p+1到n取g【i】,可以二分这个位置然后去判断f【i】和g【i】的大小就可以得出位置,然后原式变成f【1】+...f【p】+g【p+1】+...g【n】-sigma a【i】就是答案,这样是loglog的。就用sigma f【i】+sigma g【i】-n*max a【i】-sigma a【i】这个式子,难度在怎么维护f数组和g数组。

qq_73631501的博客 702

2024icpcNanjing南京(EJKBG)

补补补补

Vcoistnt的博客 441

Birthday Gift(2024 ICPC 南京站)

Birthday Gift(2024 ICPC 南京站)Grammy’s birthday is approaching, and she gets a sequence A from her friends as a gift. The sequence consists of only 0, 1, and 2. Grammy thinks that the sequence is too long, so she decides to modify A to make it shorter. Form

BoBoo文睡不醒 1993

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 248

【算法拾光】链表 哈希表|K个一组翻转链表 + 两数之和

K个一组翻转链表需分段反转,借助哑节点与前驱指针维护连接,避免断链;两数之和利用哈希表实现O(1)查找,空间换时间,高效定位目标组合。前者考察链表指针操作,后者聚焦映射关系构建,均为面试高频题。

wuqingyigexiaoba的博客 320

把 KV Cache 压到 FP4:BitDecoding-FP4 的算法-系统协同设计复盘

长上下文推理卡在KV Cache的显存与带宽上,而现有FP4方案要么精度崩、要么速度废。这篇文章复盘BitDecoding-FP4如何用三个算法补丁加一个系统重构,在B300上把服务吞吐提升2.4–3.0倍,精度几乎不掉。

helloagent的博客 193

排序算法深度笔记(下):非比较类排序的线性突破与工程边界

排序算法时间复杂度额外空间复杂度稳定性是否基于比较选择排序O(N^2)(O(1))不稳定是冒泡排序O(N^2)(O(1))稳定是插入排序O(N^2)(O(1))稳定是归并排序O(N\log N)(O(N))稳定是快速排序O(N\log N)O(log N)不稳定是堆排序O(N\log N)O(1)不稳定是计数排序(O(N + M))O(M))稳定否基数排序O(N)稳定否桶排序平均O(N) / 最坏O(N^2)

2401_87069538的博客 596

优选算法:分治-归并排序

交易逆序对的总数

Wangshijie1015的博客 136

算法日常・每日刷题--<动态规划>42

本题为“不相交的线”,与最长公共子序列问题相似。使用动态规划求解:定义 dp[i][j] 表示 nums1[0:i] 与 nums2[0:j] 的最大不相交连线数。若元素相等,则继承左上值加1;否则取上方或左方最大值。最终返回 dp[m][n],即两数组的最大不相交连线数。时间复杂度 O(mn),空间复杂度 O(mn)。

2503_92261635的博客 22
上一篇: The 2023 ICPC Asia Shenyang Regional Contest(2023沈阳区域赛CEJK)
下一篇: The 2024 ICPC Asia Hangzhou Regional Contest (2024杭州区域赛AKHEM)
西望云天
博客等级 码龄3年 74粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值