牛客算法周周练6(BCDE)

B:华华对月月的忠诚
思路:因为最后要求的是gcd(a,b),所以我一开始是分类讨论的。
如果a和b都是偶数,那么他们的斐波拉契项都是偶数,对于任意位置的n和n+1,偶数的gcd都是2.
如果a和b都是奇数,或者是奇数与偶数,他们的斐波拉契项有可能有奇数或者偶数,一开始我猜想都是1,事实上大部分都是1,但是随手打了个表就找到了反例,a=3,b=9,然后我就发现事实上这个答案就是gcd(a,b)。
代码:

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

typedef long long int ll;
void solved(){
    ll a,b,n;cin>>a>>b>>n;
    cout<<__gcd(a,b)<<endl;

}
int main(){
    solved();
    return 0;
} 

D:挖沟
这个题。。。。。裸的最小生成树。。直接上板子就行。
克鲁斯卡尔算法:存边,对边权排序,选择n-1条最小边,并且不构成回路(并查集维护).
好久没写最小生成树了,现场花了几分钟手搓了一下
代码:

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

typedef long long int ll;
const int maxn = 5e5 + 10;
struct edge{
    int u,v,w;
    edge(){}
    edge(int a,int b,int c):u(a),v(b),w(c){}
}a[maxn];
int f[maxn];
bool cmp(edge a,edge b){
    return a.w < b.w;
}
int find(int x){
    if(f[x] != x){
        return f[x] = find(f[x]);
    }
    return x;
}
void solved(){
    int n,m;cin>>n>>m;
    for(int i = 1; i <= n; i++)f[i] = i;
    for(int i = 1; i <= m; i++){
        int u,v,w;cin>>u>>v>>w;
        a[i] = {u,v,w};
    }
    sort(a + 1 ,a + 1 + m,cmp);
    int tot = 0;
    ll ans = 0;
    for(int i = 1; i <= m; i++){
        int u = a[i].u,v = a[i].v;
        int fa = find(u);
        int fb = find(v);
        if(fa != fb){
            f[fa] = fb;
            tot++;
            ans += a[i].w;
        }
        if(tot == n - 1)break;
    }
    cout<<ans<<endl;
}
int main(){
    solved();
    return 0;
}

C:Game
思路:这题从一次操作可以将集合中一个数字分解为它的任意两个非1的因数入手,首先我们可以考虑特殊的数-素数,只能分解为1*n,所以先手必败,然后再思考普遍的情况。对于一个数,我们可以一直把他拆开,直到不能再拆为止,记录我们拆的次数,如果是奇数说明后手无法继续拆,偶数先手无法拆,输出对应答案即可。
代码:

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

bool is_prime(int n){
    for(int i = 2; i * i <= n; i++){
        if(n % i == 0)return false;
    }return true;
} 
void solved(){
    int n;cin>>n;
    if(is_prime(n)){cout<<"Nancy"<<endl;return;} 
    queue<int>st;st.push(n);
    int cnt = 0;
    while(!st.empty()){
        int cur = st.front();st.pop();
        for(int i = 2; i * i  <= cur; i++){
            if(cur % i == 0){
                cnt++;
                st.push(i);st.push(cur / i);break;
            }
        }
    }
    if(cnt & 1)cout<<"Johnson"<<endl;
    else cout<<"Nancy"<<endl;
}
int main(){
    solved();
    return 0;
} 

E:签到题
思路:看到题直接就认为是记录每个数出现的次数,然后上线段树。。。。导致浪费好多时间。。还是先应该认真看题啊。。。题目意思是插入n段区间要我们就所有区间的并的个数,删除的区间必须是先前插入过的才行。
区间修改,区间求和,所以我们可以用线段树来维护,线段树维护cnt表示插入删除的次数,len表示当前区间长度。如果cnt为真说明这段区间已经插入过了,它的区间长度就是本身,否则,它的区间长度等于左右儿子的长度之和。如果插入的区间与已有的区间重合怎么处理?对于重合的区间说明之前已经插入过,它的cnt为真所以不用处理,就变成了只对没重合的处理。
代码:

#include <algorithm>
 #include <iostream>
 #include <cstring>
 #include <climits>
 #include <cstdio>
 #include <vector>
 #include <cstdlib>
 #include <ctime>
 #include <cmath>
 #include <queue>
 #include <stack>
 #include <map>
 #include <set>
 #define fi first
 #define lc (x<<1)
 #define se second
 #define U unsigned
 #define rc (x<<1|1)
 #define Re register
 #define LL long long
 #define MP std::make_pair
 #define CLR(i,a) memset(i,a,sizeof(i))
 #define FOR(i,a,b) for(Re int i = a;i <= b;++i)
 #define ROF(i,a,b) for(Re int i = a;i >= b;--i)
 #define SFOR(i,a,b,c) for(Re int i = a;i <= b;i+=c)
 #define SROF(i,a,b,c) for(Re int i = a;i >= b;i-=c)
 #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
 using namespace std;
 const int MAXN = 1000000+5;
 int N,maxL;
 std::set<std::pair<int,int> > L;

const int maxn = 1e6 + 10;
struct seg{
    int l,r,cnt;
    int len;
    seg(){}
    seg(int a,int b):l(a),r(b){}
}tree[maxn << 2];
void build(int rt,int l,int r){
    tree[rt] = {l,r};
    if(l == r){
        tree[rt].len = 0;
        tree[rt].cnt = 0;
        return;
    }
    int mid = l + r >> 1;
    build(rt << 1,l, mid);
    build((rt << 1) + 1,mid + 1,r);
    tree[rt].cnt = 0;
    tree[rt].len = 0;
}

void update(int rt ,int l,int r,int v){
    if(tree[rt].l >= l && tree[rt].r <= r){
        tree[rt].cnt += v;
        if(tree[rt].cnt)tree[rt].len = (tree[rt].r - tree[rt].l + 1);
        else {tree[rt].len = tree[rt << 1].len + tree[rt << 1 | 1].len;}
        return ;
    }
    int mid = tree[rt].l + tree[rt].r >> 1;
    if(r <= mid) update(rt << 1,l,r,v);
    else if(l > mid) update((rt << 1) + 1,l,r,v); 
    else update(rt << 1,l,r,v),update((rt << 1) + 1,l,r,v);
    if(tree[rt].cnt)tree[rt].len = (tree[rt].r - tree[rt].l + 1);
    else {tree[rt].len = tree[rt << 1].len + tree[rt << 1 | 1].len;}
} 
int main(){
     scanf("%d%d",&N,&maxL);
     build(1,1,maxL);
     while(N--){
         int opt,x,y;
         scanf("%d%d%d",&opt,&x,&y);
         if(opt == 1){
             if(L.find(MP(x,y)) != L.end()) continue;
             L.insert(MP(x,y));
             update(1,x,y,1);
         }
         if(opt == 2){
             if(L.find(MP(x,y)) == L.end()) continue;
             L.erase(MP(x,y));
             update(1,x,y,-1);
         }
         if(opt == 3){
             printf("%d\n",tree[1].len);
         }
     }
     return 0;
 }
算法周周练 文章被收录于专栏

算法周周练题解

全部评论

相关推荐

暴杀流调参工作者:春招又试了一些岗位,现在投递很有意思,不仅要精心准备简历,投递官网还得把自己写的东西一条一条复制上去,阿里更是各个bu都有自己的官网,重复操作无数次,投完简历卡完学历了,又该写性格测评、能力测评,写完了又要写专业笔试,最近还有些公司搞了AI辅助编程笔试,有些还有AI面试,对着机器人话也听不明白录屏硬说,终于到了人工面试又要一二三四面,小组成员面主管面部门主管面hr面,次次都没出错机会,稍有不慎就是挂。 卡学历卡项目卡论文卡实习什么都卡,没有不卡的😂
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
正在热议
更多
# AI面会问哪些问题? #
24308次浏览 477人参与
# 中国电信笔试 #
30930次浏览 283人参与
# 米连集团26产品管培生项目 #
12908次浏览 285人参与
# 你的实习产出是真实的还是包装的? #
18515次浏览 329人参与
# 如果秋招能重来,我会____ #
96448次浏览 499人参与
# 春招至今,你的战绩如何? #
59119次浏览 535人参与
# 开放七大实习专项,百度暑期实习值得冲吗 #
13981次浏览 208人参与
# i人适合做什么工作 #
36646次浏览 123人参与
# 我是面试官,请用一句话让我破防 #
79291次浏览 219人参与
# 哪些公司真双非友好? #
69122次浏览 287人参与
# 找AI工作可以去哪些公司? #
7473次浏览 177人参与
# 从事AI岗需要掌握哪些技术栈? #
7465次浏览 235人参与
# 五一之后,实习真的很难找吗? #
102791次浏览 584人参与
# 投递几十家公司,到现在0offer,大家都一样吗 #
339717次浏览 2163人参与
# 你做过最难的笔试是哪家公司 #
29501次浏览 179人参与
# 你小时候最想从事什么职业 #
159826次浏览 2072人参与
# 阿里笔试 #
175963次浏览 1299人参与
# 金三银四,你的春招进行到哪个阶段了? #
21407次浏览 274人参与
# 一张图晒出你司的标语 #
3779次浏览 71人参与
# 面试被问期望薪资时该如何回答 #
382432次浏览 2163人参与
# 晶盛机电求职进展汇总 #
35209次浏览 318人参与
# 应届生第一份工资要多少合适 #
20440次浏览 84人参与
牛客网
牛客网在线编程
牛客网题解
牛客企业服务