2024牛客寒假算法基础集训营2

news2025/2/25 15:53:01

目录

A.Tokitsukaze and Bracelet

B.Tokitsukaze and Cats

C.Tokitsukaze and Min-Max XOR

D.Tokitsukaze and Slash Draw

E and F.Tokitsukaze and Eliminate (easy)(hard)

G.Tokitsukaze and Power Battle (easy)

暂无

I.Tokitsukaze and Short Path (plus)

J.Tokitsukaze and Short Path (minus)

K.Tokitsukaze and Password (easy)


A.Tokitsukaze and Bracelet

阅读理解题,读懂题目按照要求模拟即可,重复的计算使用函数来解决

void solve(){
   
    int a,b,c; cin>>a>>b>>c;
    int ans=0;
    if(a==150) ans=1;
    if(a==200) ans=2;
    auto get = [&](int x){
        if(x>=29 && x<=32) return 0;
        if(x==45) return 2;
        return 1;
    };
    ans+=get(b)+get(c);
    cout<<ans<<endl;
    return ;
}

B.Tokitsukaze and Cats

我们要计算的是贡献,一个猫带来的贡献是看周围有没有其他的猫导致重复的所以我们就直接用

st[M][M]表示找个位置有没有猫然后看周围位置是不是有猫即可

bool st[M][M];
void solve(){
    cin>>n>>m>>k;
    int ans=0;
    while(k--){
        int a,b; cin>>a>>b;
        ans+=!st[a-1][b];
        ans+=!st[a+1][b];
        ans+=!st[a][b-1];
        ans+=!st[a][b+1];
        st[a][b]=true;
    }
    cout<<ans<<endl;
    return ;
}

C.Tokitsukaze and Min-Max XOR

1.记录方案数从数组中选一堆数出来的

2.与两个数异或<=k

接着分析我们可以发现选出这一堆数其实和整个数中有用的其实只有最大值和最小值,其他的都是看贡献即可

由此假设不考虑其他数的选择题目变成了选两个数异或小于等于k这也就是经典的trie树求解,但是考虑到树上的话,我们也是可以按照从小到大来排序不影响选择吗,同时保证到i的时候是最大值,那么贡献是什么呢贡献就是找到前面的一个满足的数后中间的数可选可不选2^{r-l-1}也就是\frac{2^{r-1}}{2^l}

也就是前面的数的贡献是后面的除以他那么我怎么记录前面的数的贡献呢?我们发现本题要的是逆元所以除以一个数可以变成乘以一个数的逆元由此 前缀可以用trie数+逆元的贡献来记录即可

然后就是普通的操作了

LL tr[N*32][2],cnt[N*32],idx;

LL qmi(LL a,LL b){
    LL res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
LL inv(LL x){
    return qmi(x,mod-2);
}
void insert(int x,LL val){
    int p=0;
    for(int i=30;i>=0;i--){
        int u=x>>i&1;
        if(!tr[p][u]) tr[p][u]=++idx;
        p=tr[p][u];
        (cnt[p]+=val)%mod;
    }
}
LL query(int x,int y){
    int p=0;
    LL res=0;
    for(int i=30;i>=0;i--){
        int ux=x>>i&1,uy=y>>i&1;
        if(uy){
            res=(res+cnt[tr[p][ux]])%mod;
            if(!tr[p][!ux]) return res;
            p=tr[p][!ux];
        }
        else{
            if(!tr[p][ux]) return res;
            p=tr[p][ux];
        }
    }
    res=(res+cnt[p])%mod;
    return res;
}

void intn(){
    for(int i=0;i<=idx;i++)
        for(int j=0;j<=1;j++)
            tr[i][j]=0,cnt[i]=0;
    idx=0;
}
void solve(){
    intn();
    cin>>n>>k;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a.begin()+1,a.end());
    LL ans=0;
    for(int i=1;i<=n;i++){
        (ans+=query(a[i],k)*qmi(2,i-1)%mod+1)%=mod;
        insert(a[i],inv(qmi(2,i)));
    }
    cout<<ans<<endl;
   
    return ;
}

D.Tokitsukaze and Slash Draw

典型的轮换变化我们可以直接抽象为图论,由于是最优解也就是最快抵达这个点的解把数和数之间的转化直接看成边即可,然后用dijkstra,由于要他排在第k张牌也就是抽走上面的n-k张牌符合边的要求接着就是初始的时候是0用map存边的最小值减少方案注意LL

void solve(){
    
    cin>>n>>m>>k;
    unordered_map<int,int> mp;
    for(int i=1;i<=m;i++){
         int x,y; cin>>x>>y;
         x%=n;
         if(!mp.count(x)) mp[x]=y;
         else mp[x]=min(mp[x],y);
    }
    int need=n-k;
    auto dijkstra = [&](){
        vector<bool> st(n+5);
        for(int i=1;i<=n;i++) d[i]=2e18;
        priority_queue<PII,vector<PII>,greater<PII>> q;
        q.emplace(0,0);
        while(!q.empty()){
            auto [cost,u]=q.top(); q.pop();
            if(st[u]) continue;
            st[u]=true;
            if(u==need) return cost;
            for(auto&[v,w]:mp){
                int ne=(u+v)%n;
                if(d[ne]>cost+w){
                    d[ne]=cost+w;
                    q.emplace(d[ne],ne);
                }
            }
        }
        return (LL)-1;
    };
     
    cout<<dijkstra()<<endl;
    return ;
}

E and F.Tokitsukaze and Eliminate (easy)(hard)

做题的时候特别是计算贡献的时候一定要找到贡献的来源,我们可以发现消除一个数(如果找个数在右边第一次出现)之后其最右边的数都会消失,那么怎么做的贡献最少呢,当然十当前数组的每一个数都出现的时候最优的这样的删除一次删除的数最多可以(j结论明显所以直接用map存书的数量即可然后删除)这种最优性贡献都是如此思考

1.贡献来源

2.如何减少贡献

3.贡献是否最优

int a[N];
void solve(){
   
    map<int,int> mp,cnt;
    cin>>n;
    for(int i=1;i<=n;i++){
         cin>>a[i];
         cnt[a[i]]++;
    }
    int ans=0;
    for(int i=n;i>=1;i--){
        mp[a[i]]++;
        cnt[a[i]]--;
        if(mp.size()==cnt.size()){
            ans++;
            for(auto&[v,w]:mp){
                if(cnt[v]==0) cnt.erase(v);
            }
            mp.clear();
        }
    }
    cout<<ans<<endl;
    return ;
}

G.Tokitsukaze and Power Battle (easy)

我们来看看看题目的性质

1.每一个数都是大于等于0的数

2.我要的是[l,r]整个区间中选出一个子区间[ll,rr]中间找一个点[ll,x][x+1,rr]使得左边减去右边最小

做法一:线段树

由此我们可以发现左边的ll==l一定是最好的由条件1的不会变差,考虑右边那么一定是取一个数,

那么取哪一个数呢我们要求的就是sum[l,x]-a[x]\left (l<x<=r\right )变形之后sum_{y-1}-sum_{l-1}-a_y =sum_y-2*a_y-sum_{l-1} 也就是我们统一了下标得出维护的是区间中的sum_y-2*a_y,此时变成了区间维护整个值也就是区间修改需要懒标记维护同时维护前缀和,所以对于这个区间中除了y之外的数都是-change+before,对其单独处理即可

int w[N];
LL s[N];
struct code{
    int l,r;
    LL val,ans;
    LL tag;
}tr[4*N];
void pushup(code&u,code&l,code&r){
    u.val=l.val+r.val;
    u.ans=max(l.ans,r.ans);
}
void pushup(int u){
    pushup(tr[u],tr[u<<1],tr[u<<1|1]);
}
void pushdown(code&u,code&l,code&r){
    if(u.tag){
        l.ans+=u.tag,r.ans+=u.tag;
        l.tag+=u.tag,r.tag+=u.tag;
        u.tag=0;
    }
}
void pushdown(int u){
    pushdown(tr[u],tr[u<<1],tr[u<<1|1]);
}

void build(int u,int l,int r){
    if(l==r){
        tr[u]={l,l,w[l],s[l]-2*w[l]};
        return ;
    }
    tr[u]={l,r,0,(LL)-1e18};
    int mid=l+r>>1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    pushup(u);
}

void modify(int u,int l,int r,int x,int op){
    if(l<= tr[u].l&& tr[u].r <=r){
       if(op==1)
           tr[u].ans+=x,tr[u].tag+=x;
       else 
           tr[u].val=x;
        return ;
    }
    pushdown(u);
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid) modify(u<<1,l,r,x,op);
    if(r>mid) modify(u<<1|1,l,r,x,op);
    pushup(u);
}

LL query(int u,int l,int r,int op){
    if(l<=tr[u].l && tr[u].r<=r){
        return op==1 ? tr[u].val : tr[u].ans;
    }
    int mid=tr[u].l+tr[u].r>>1;
    LL res= op==1 ? 0 : -1e18;
    pushdown(u);
    if(r<=mid){
        if(op==1) res+=query(u<<1,l,r,op);
        else res=max(res,query(u<<1,l,r,op));
    }
    else if(l>mid){
        if(op==1) res+=query(u<<1|1,l,r,op);
        else res=max(res,query(u<<1|1,l,r,op));
    }
    else{
        if(op==1) res=res+query(u<<1,l,r,op)+query(u<<1|1,l,r,op);
        else res=max({res,query(u<<1,l,r,op),query(u<<1|1,l,r,op)});
    }
    return res;
}
void solve(){
   
    cin>>n>>m;
    for(int i=1;i<=n;i++){
         cin>>w[i];
         s[i]=s[i-1]+w[i];
    }
    
    build(1,1,n);
    
    while(m--){
        int op,l,r; cin>>op>>l>>r;
        if(op==1){
            modify(1,l,n,r-w[l],1);
            modify(1,l,l,-2*r+2*w[l],1);
            w[l]=r;
            modify(1,l,l,w[l],2);
        }
        else{
            LL res=query(1,l+1,r,2);
            if(l-1>=1) res-=query(1,1,l-1,1);
            cout<<res<<endl;
        }
    }
    return ;
}

做法二:树状数组

我们考虑对后缀进行移动最开始是 sum_r-sum_{l-1}-2*a_r

移动一位sum_r-sum_{l-1}-a_r-2*a_{r-1}

假设移动 一位地 贡献要大于上一位的话2*a_{r-1}<2*a_r 所以我们最多移动检查的位数就是32位这样可以直接用树状数组来维护

int w[N];
struct BIT{
    int tr[N];
    // int inline lowbit(int x){
        // return x&(-x);
    // }
    void add(int k,int x){
        for(int i=k;i<=n;i+=lowbit(i)) tr[i]+=x;
    }
    int query(int k){
        int res=0;
        for(int i=k;i;i-=lowbit(i)) res+=tr[i];
        return res;
    }
    int ask(int l,int r){// 先左再右
        return query(r)-query(l-1); 
    }
    void clear(){
        for(int i=0;i<=n+2;i++) tr[i]=0;
    }
}tree;

void solve(){
   
    
    cin>>n>>m;
    tree.clear();
    for(int i=1;i<=n;i++){
         cin>>w[i];
         tree.add(i,w[i]);
    }
    
    while(m--){
        int op,l,r; cin>>op>>l>>r;
        if(op==1){
            tree.add(l,r-w[l]);
            w[l]=r;
        }
        else{
            int ans=-1e18;
            for(int i=r-1;i>=max(r-32,l);i--){
                ans=max(ans,tree.ask(l, i)-w[i+1]);
            }
            cout<<ans<<endl;
        }
    }
    return ;
}

I.Tokitsukaze and Short Path (plus)

这是明显的计算贡献的题目我们看边的贡献是啥|a_v+a_u|+|a_v-a_u| = 2*max(a_u,a_v)

也就是说两个点之间的边贡献就是两个中的最大值的两倍,我们要计算的是\sum_i^n\sum_j^ndist_{i,j}

所以我们来看每一个点之间带来的贡献 如果直接抵达的话i和其他所有点的贡献是两者中的最大值

也就是一个点a和比他小的点的贡献就是dist_{a,i}=dist_{i,a}=a_i,同时简单思考两个点直接的最短路会不会中间有过度点,可以发现明显没有假设有的话可以简单论证一定比我现在找个要大,所以找个是最优的贡献,照权重由小到大排序之后sum=\sum_i^n2*a_i*(i-1)*2,注意开long long

void solve(){
   
    LL sum=0;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    for(int i=1;i<=n;i++){
        sum+=4*(LL)(i-1)*a[i];
    }
    cout<<sum<<endl;
    return ;
}

J.Tokitsukaze and Short Path (minus)

同上我们分析贡献dist_{u,v}=|a_u+a_v|-|a_u-a_v|=min(a_u,a_v)所以这次变成两个点中最小的了,但是如果直接同上一题是不是最优的呢?我们要考虑是否有中间点过度我们可以发现如果过度的是最小值a_1我们无法确定最优所以最优就是两者取最小值(也就是考虑齐全看我们的贡献是否是最优的) disti,j=min(2*a_1,min(a_i,a_j))

接着同上计算即可注意long long

int a[N];
void solve(){
   
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    sort(a+1,a+1+n);
    LL sum=0;
    for(int i=1;i<=n;i++){
        sum+=4ll*(n-i)*min(2*a[1],a[i]);
    }
    cout<<sum<<endl;
    return ;
}

K.Tokitsukaze and Password (easy)

首先我们读懂题目意思也就是我们需要的是 

1.没有前导0 

2.是8的倍数

3.<=y

4.其中的abcd字母是同字母数字相同不同字母数字不同(1-9),'-'只有一个也是1-9

数据范围1<=n<=9

首先我们可以发现整个数字的变化其实只有5^9所以我们可以考虑dfs直接暴力枚举所有情况即可

然后按照条件一个一个来

1. 特殊如果只有一个数可以为0,其他的如果有变化的话就是 从1开始,否则就是不满足要求

2&&3.由于数目较少到最后直接判断即可

4.(1)dfs枚举情况用map存储,同时st记录这个数是不是重复出现,同时记得还原现场

   (2)'-'直接枚举

   (3)枚举的同时需要满足没有前导0的要求

然后我们按照这个思考大纲书写代码即可

map<char,int> mp;
bool st[10];
void dfs(int u,LL res){
    if(u==n){
        if(res<=y && res%8==0) cnt++;
        return ;
    }
    if(s[u]>='0' && s[u]<='9'){
        if(s[u]=='0' && (!u && n!=1)) return ;
        dfs(u+1,res*10+(s[u]-'0'));
    }
    else if(s[u]=='_'){
        for(int i=(u==0 ? (n==1 ? 0 : 1) : 0);i<=9;i++){
            dfs(u+1,res*10+i);
        }
    }
    else{
        if(mp.count(s[u])) dfs(u+1,res*10+mp[s[u]]);
        else{
            for(int i=(u==0 ? (n==1 ? 0 : 1) : 0);i<=9;i++){
                if(st[i]) continue;
                mp[s[u]]=i;
                st[i]=true;
                dfs(u+1,res*10+i);
                st[i]=false;
                mp.erase(s[u]);
            }
        }
    }
}
void solve(){
    memset(st,0,sizeof st);
    mp.clear(); cnt=0;
    cin>>n>>s>>y;
    dfs(0,0);             
    cout<<cnt<<endl;
    return ;
}

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

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

相关文章

P0故障应对策略之:为什么P0故障难以排查

与大模型探讨P0故障 P0级故障&#xff0c;作为系统中最严重的故障&#xff0c;它们的发生往往带来灾难性的后果和巨大的损失。同时&#xff0c;这类故障的排查与修复也往往复杂而棘手&#xff0c;对整个团队的经验、综合能力、应急处置流程都是巨大的挑战。 排查P0级故障的过程…

react useMemo 用法

1&#xff0c;useCallback 的功能完全可以由 useMemo 所取代&#xff0c;如果你想通过使用 useMemo 返回一个记忆函数也是完全可以的。 usecallback(fn,inputs)is equivalent to useMemo(()> fn, inputs). 区别是:useCallback不会执行第一个参数函数&#xff0c;而是将它返…

linux查看socket信息

netstat netstat 是一个用于显示网络相关信息的命令行工具。它可以显示当前系统的网络连接状态、路由表、接口统计信息等。 下面是一些常见的 netstat 命令选项和用法&#xff1a; 显示所有活动的网络连接&#xff1a; netstat -a 显示所有正在监听的端口&#xff1a; ne…

TiDB之分布式数据库TiDB 操作管理规范【附可下载文档】

一、 目的 为了在软件生命周期内规范数据库相关的设计、开发、运维工作,便于不同团队之间的沟通及协调,制定此文档,以期在相关规范上达成共识和默契,提升相关环节的工作效率及系统的可维护性。同时好的规范,在执行的时候可以培养出好的习惯,好的习惯是软件质量的很好保证…

飞行棋网站源码

最近抖音很火的情侣飞行棋网站源码&#xff0c;这款情侣飞行棋提供了丰富的游戏玩法&#xff0c;可以为情侣、朋友或家人带来欢乐的游戏体验。无论是在家中&#xff0c;还是在聚会、旅行等场合&#xff0c;都可以轻松启动该网站&#xff0c;共同享受游戏的乐趣。 源码获取搜一搜…

【BUG 记录】史诗级 BUG - MYSQL 删库删表却没有备份如何恢复数据

【BUG 记录】史诗级 BUG - MYSQL 删库删表却没有备份如何恢复数据 1. 问题描述2. 解决方案&#xff08;binlog&#xff09;2.1 构造测试环境2.2 查看 MySQL 环境是否开启 binlog2.3 查看所有的 binlog 日志记录2.4 查看当前正在使用的是哪一个 binlog 文件2.5 查看此时的 binlo…

Redis 发布订阅详解

Redis 发布订阅 Redis 发布订阅 (pub/sub) 是一种消息通信模式&#xff1a;发送者 (pub) 发送消息&#xff0c;订阅者 (sub) 接收消息。Redis 客户端可以订阅任意数量的频道。 Redis 有两种发布订阅模式 基于频道&#xff08;Channel&#xff09;的发布订阅基于模式&#xff…

腾讯云4核8G服务器有用过的吗?性能咋样?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

MySQL进阶45讲【26】主库出问题了,从库怎么办?

1 前言 在前面的MySQL进阶45讲【23】MySQL是怎么保证主备一致的&#xff1f;、MySQL进阶45讲【24】MySQL是怎么保证高可用的&#xff1f;和MySQL进阶45讲【25】备库为什么会延迟好几个小时&#xff1f;3篇文章中&#xff0c;介绍了MySQL主备复制的基础结构&#xff0c;但这些都…

Python算法100例-2.5 存钱

完整源代码项目地址&#xff0c;关注博主私信源代码后可获取 1.问题描述2.问题分析3.算法设计4.确定程序框架5.完整的程序 1&#xff0e;问题描述 假设银行整存整取存款不同期限的月利率为&#xff1a; 0.63%&#xff0c;期限为1年&#xff1b; 0.66%&#xff0c;期限为2年…

Java练习(第4天)【总结】反转字符串的9种不同实现方法

一、问题描述 给定一个字符串&#xff0c;输出反转后的字符串。 样例输入1: abc 样例输出1: cba 样例输入2: GeeksforGeeks 样例输出2: skeeGrofskeeG 二、Java实现&#xff08;九个程序&#xff09; 1、实现1 思想&#xff1a; 逐个取 倒序拼 Java代码&#xff1a; i…

测试开发(6)软件测试教程——自动化测试selenium(自动化测试介绍、如何实施、Selenium介绍 、Selenium相关的API)

接上次博客&#xff1a;测试开发&#xff08;5&#xff09;测试分类标准 &#xff1a;按测试对像划分、按是否查看代码划分、按开发阶段划分、按测试实施组织、按是否运行划分、按是否手工划分、按测试地域划分-CSDN博客 目录​​​​​​​ 什么是自动化测试 自动化测试介绍…

【Unity自制手册】Unity—Camera相机跟随的方法大全

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

微信小程序蓝牙通信HC08

总结这两天研究的蓝牙串口。人话版资料不多&#xff0c;主要靠翻别人的仓库和文档。 单片机部分&#xff0c;与蓝牙串口通信是通过串口。比我想的要简单&#xff0c;小程序部分&#xff0c;有非常多的服务和特征&#xff0c;而且人话版资料不多。 如果本文有什么问题&#xf…

C# 水排序 微信小游戏

来只 水排序谜题启发式搜索方法_水排序解法小程序-CSDN博客 大神的C语言转换成C# 语言&#xff0c;更多的请看原作者&#xff0c;这里直接贴C#代码 using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace ConsoleApp2 {class Pro…

再见,Visual Basic——曾经风靡一时的编程语言

2020年3月&#xff0c;微软团队宣布了对Visual Basic&#xff08;VB&#xff09;的“终审判决”&#xff1a;不再进行开发或增加新功能。这意味着曾经风光无限的VB正式退出了历史舞台。 VB是微软推出的首款可视化编程软件&#xff0c;自1991年问世以来&#xff0c;便受到了广大…

vue插件——vue-print-nb 实现打印功能

之前写过好多关于打印的功能&#xff0c;通过windowprint组合键来实现打印。 今天遇到一个需求&#xff0c;就是使用vue插件来实现打印功能。 最终效果图如下&#xff1a; 下面介绍解决步骤&#xff1a; 解决步骤1&#xff1a;安装vue-print-nb插件——npm install vue-p…

2024年,“智慧城市”到底是持续拉跨还是稳步向前?

2024年“智慧城市”的发展趋势&#xff0c;总体上来看&#xff0c;是稳步向前的。 随着科技的不断发展&#xff0c;特别是物联网、云计算、大数据、人工智能等技术的日益成熟和普及&#xff0c;智慧城市的建设有了更为坚实的基础。这些技术不仅可以帮助城市实现更高效、智能的…

智慧公厕让社区生活更美好

随着科技的迅猛发展&#xff0c;城市管理、城市服务均使用科技化的手段进行升级改造&#xff0c;社区生活更美好赋予全新的智慧效能&#xff0c;其中智慧公厕也成为了城市环卫设施的新宠。智慧公厕以物联网、互联网、大数据、云计算、5G通信、自动化控制等技术为核心&#xff0…

Leetcoder Day23| 回溯part03:组合+分割

语言&#xff1a;Java/Go 39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的所有不同组合 &#xff0c;并以列表形式返回。你可以按任意顺序返回这些组合。 candidates 中的同一个…