牛客寒假算法训练营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;
}
相关推荐
Old Uncle Tom6 分钟前
OpenClaw 记忆系统 -- 记忆预加载
java·数据结构·算法·agent
会编程的土豆16 分钟前
洛谷题单入门1 顺序结构
数据结构·算法·golang
生信碱移18 分钟前
PACells:这个方法可以鉴定疾病/预后相关的重要细胞亚群,作者提供的代码流程可以学习起来了,甚至兼容转录组与 ATAC 两种数据类型!
人工智能·学习·算法·机器学习·数据挖掘·数据分析·r语言
智者知已应修善业38 分钟前
【51单片机中的打飞机设计】2023-8-25
c++·经验分享·笔记·算法·51单片机
智者知已应修善业3 小时前
【51单片机按键调节占空比3位数码管显示】2023-8-24
c++·经验分享·笔记·算法·51单片机
.5484 小时前
## Sorting(排序算法)
python·算法·排序算法
wuweijianlove4 小时前
算法的平均复杂度建模与性能回归分析的技术7
算法·数据挖掘·回归
子琦啊4 小时前
【算法复习】字符串 | 两个底层直觉,吃透高频题
linux·运维·算法
code_pgf5 小时前
Octo 算法详解-开源通用机器人策略模型技术报告
算法·机器人·开源
嘻嘻哈哈樱桃6 小时前
牛客经典101题题解集--动态规划
java·数据结构·python·算法·职场和发展·动态规划