牛客寒假算法训练营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;
}
相关推荐
甄心爱学习2 小时前
【python】获取所有长度为 k 的二进制字符串
python·算法
iAkuya2 小时前
(leetcode)力扣100 76数据流的中位数(堆)
算法·leetcode·职场和发展
键盘鼓手苏苏2 小时前
Flutter for OpenHarmony: Flutter 三方库 ntp 精准同步鸿蒙设备系统时间(分布式协同授时利器)
android·分布式·算法·flutter·华为·中间件·harmonyos
董董灿是个攻城狮2 小时前
AI 视觉连载5:传统 CV 之均值滤波
算法
多恩Stone3 小时前
【3D-AICG 系列-11】Trellis 2 的 Shape VAE 训练流程梳理
人工智能·pytorch·算法·3d·aigc
lintax3 小时前
计算pi值-积分法
python·算法·计算π·积分法
你的冰西瓜4 小时前
C++ STL算法——排序和相关操作
开发语言·c++·算法·stl
今儿敲了吗4 小时前
29| 高考志愿
c++·笔记·学习·算法
识君啊5 小时前
Java 二叉树从入门到精通-遍历与递归详解
java·算法·leetcode·二叉树·深度优先·广度优先