牛客寒假算法训练营2

A(签到)

B(贪心)

显然 当最大值的数目为奇数的时候 只有最大值可以留到最后 当最大值的数目为偶数的时候 显然除了最大值本身 任何数字都可以留到最后

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
pair<int,int>a[N];
int b[N];
int n;
void solve(){
    cin>>n;
    int maxn=0;
    int cnt=0;
    for(int i=1;i<=n;i++){
        cin>>a[i].first;
        b[i]=a[i].first;
        maxn=max(maxn,a[i].first);
        a[i].second=i;
    }
    for(int i=1;i<=n;i++){
        if(a[i].first==maxn)cnt++;
    }
    if(cnt%2==1){
        for(int i=1;i<=n;i++){
            if(a[i].first==maxn)cout<<1;
            else cout<<0;
        }
        cout<<'\n';
    }else{
        for(int i=1;i<=n;i++){
            if(a[i].first==maxn)cout<<0;
            else cout<<1;
        }
        cout<<'\n';
    }
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;cin>>t;
    while(t--)solve();
    return 0;
}

C()

D()

E(构造)

给定一个整数n,要求构造一个n×n的01矩阵同时满足下列条件: 1. 每一行数字的和构成{0,1,2,3,··· ,n−1} 的数字集合。 2. 每一列数字的和构成{0,1,2,3,··· ,n−1} 的数字集合。 3. 数字连通块恰好有n个。 数据范围: 1≤n≤1000

题解:例如: n=6

000000

011111

010000

010111

010100

010101

考虑上图的矩阵,行从0∼n-1,列从0∼n-1,对于(i,j)的答案为 min(i,j) AND 1。 AND: 位运算中的按位与。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            int num=min(i,j)&1;
            cout<<num;
        }
        cout<<'\n';
    }    
    return 0;
}

F(位运算 构造)

题目描述 给定一个整数n,构造两个不相等的整数x,y 满足gcd(x,y)=n 且 x ⊕y 最小。 数据范围: 1≤T ≤10^4,1≤n≤10^6

题解:gcd(x,y)=n 我们可以得出x ,y 是n的倍数 并且若x = an y=bn a 与 b互质

异或运算同为1减 不同则加 那么一定有|x −y|≤x ⊕y, x-y的最小值也就是(a-b)n 相邻两个数字一般互质 那么这个值就可以取到1 我们要构造两个数字 使得他俩异或的值等于相减的值也就是n 那么假设n二进制有k位 我们就可以取n<<k 和 (n<<k ) + n 这两个数字 高位直接减去 低位相加 这样结果就是n

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
#define int long long
void solve(){
    int n;cin>>n;
    int k=1;
    while(k<=n){
        k<<=1;  
    }
    int x=n*k;
    int y=n*(k+1);
    cout<<x<<" "<<y<<'\n';
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;cin>>t;
    while(t--)solve();
    return 0;
}

H(贡献法)

定义一个数组的权值为其所有前缀中不同数字的个数,求所有子数组的 权值之和。

'题解 : 我们可以考虑贡献法 考虑一个数字能给多少个子数组贡献答案以及贡献的大小 当计算a[i]的时候一定包含i本身这个位置 那么我们要考虑 上一个a[i]的位置 j 那么左端点的选择方法有i-j个 右端点的选择方法就有n-i+1 种 那么也就是说 我们可以找到(i-j)*(n-i+1)个子数组 这些子数组又会有各自的前缀 只有覆盖i的前缀才能产生贡献 当左端点固定的时候 右端点产生的n-i+1个子数组 的有效前缀(覆盖位置i)分别有1 2 3 4 5 6 7 .。。(n-i+1) 个 那么也就是总共 (n−i+1)×(n−i+1+1)/2 个前缀 再乘上左端点的个数即可

代码:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
#define int long long
int a[N];
int n;
void solve(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    unordered_map<int,int>p;    //维护这个数字上一次出现的位置
    int ans=0;
    for(int i=1;i<=n;i++){
        int num=a[i];
        int pr=0;
        if(p.find(a[i])!=p.end()){
            pr=p[num];
        }
        int numl=i-pr;
        int numr=n-i+1;
        ans+=1LL*numl*numr*(numr+1)/2;
        p[num]=i;
    }
    cout<<ans<<'\n';
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;cin>>t;
    while(t--)solve();
    return 0;
}

I()

大致题意: 一个01矩阵 判断从每一个位置出发 是否都有一条路径 使得路径上所有字符构成的字符串是一个回文串

题解: 我们可以先找到一个终点 和起点相同 若没有显然不成立 找到终点后 我们可以向四周扩展 如果二者有相同的相邻字符 就可以扩展 如果没有 说明这个终点的四周的字符和终点本身相同 那么我们可以不断移动终点 使得二者有相同的相邻字符 不断找下去 就可以发现 只要有两个相同的点 那么最终一定会有一个回文串 只需要判断 0 和1 的数目就可以了

代码不再演示

J(图论、BFS、最短路)

要算出每个点前往更高等级的点的最短路 这里的等级 就是每个点的度数 最朴素的想法 我们可以对每个点进行bfs 这样一定可以解决问题 但是时间复杂度过高 o(nm);

想要优化 我们可以从高等级开始向低等级bfs 因为如果高等级bfs完后 当前等级仍然没有答案 那么他就一定不会有答案了 但是如果从低等级遍历 会导致重复 时间复杂度高

按照这种思路跑一边bfs即可

代码实现如下

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m;
int deg[N];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    vector<int>e[N];
    cin>>n>>m;

    for(int i=1;i<=m;i++){
        int u,v;cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
        deg[u]++;deg[v]++;
    }    
    map<int,deque<int>>mp;
    for(int i=1;i<=n;i++){
        mp[deg[i]].push_back(i);
    }
    vector<int>dis(n+1,1e9),ans(n+1);
    for(auto it=mp.rbegin();it!=mp.rend();it++){
        auto x=it->first;
        auto &q=it->second;
        for(auto &i :q){
            if(dis[i]>1e8)dis[i]=-1;
            ans[i]=dis[i];
            dis[i]=0;
        }
        while(q.size()){
            auto u=q.front();
            q.pop_front();
            for(auto v:e[u]){
                if(deg[v]>=x)continue;
                if(dis[v]>dis[u]+1){
                    dis[v]=dis[u]+1;
                    q.push_back(v);
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<' ';
    }
    cout<<'\n';
    return 0;
}
相关推荐
沉鱼.443 分钟前
第十五届题目
linux·运维·算法
我头发多我先学7 分钟前
C++ STL vector 原理到模拟实现
c++·算法
机器学习之心10 分钟前
信号分解和小波阈值联合降噪 | NRBO-FMD基于牛顿拉夫逊算法优化特征模态分解+皮尔逊系数+小波阈值降噪+信号重构,MATLAB代码
算法·matlab·重构·nrbo-fmd·特征模态分解
Lauren_Blueblue13 分钟前
第十六届蓝桥杯省赛Python研究生组-F串
python·算法·蓝桥杯·算法基础
鲸渔14 分钟前
【C++ 入门】第一个程序:Hello World 与基本语法规则
开发语言·c++·算法
‎ദ്ദിᵔ.˛.ᵔ₎15 分钟前
滑动窗口算法
算法·哈希算法
sali-tec16 分钟前
C# 基于OpenCv的视觉工作流-章46-矩形卡尺
图像处理·人工智能·opencv·算法·计算机视觉
仟濹18 分钟前
【算法打卡day39(2026-04-06~08 周一~周三)】(10道蓝桥杯真题)今日练习:蓝桥杯第13届省赛B组Cpp组
算法·职场和发展·蓝桥杯
美式请加冰23 分钟前
最短路径问题
java·数据结构·算法
会编程的土豆23 分钟前
【数据结构与算法】 时间复杂度计算
数据结构·c++·算法