牛客小白月赛12(部分题解)

本文精选了算法竞赛中的典型题目,包括贪心算法、Java大数处理、线性筛法、二分查找、树状数组、最大公约数、tarjan算法及STL字符串应用等,提供了详细的解题思路和代码实现。

链接:https://ac.nowcoder.com/acm/contest/392#question
来源:牛客网



华华听月月唱歌(贪心)

?题目地址:https://ac.nowcoder.com/acm/contest/392/A ?

一道简单的贪心,做炸了,选择最右端区间的时候没有维护好,只过了70%的数据.这道题的解法是先将区间排序,然后遍历这些区间,对于有重合的区间,我们就选择右端点最远的区间即可.

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int Max_n=100005;
typedef long long LL;

struct A{
	int l,r;
}a[Max_n];

bool operator <(const A &a,const A &b){
	if(a.l==b.l)
		return a.r>b.r;
	return a.l<b.l;
}

int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%d%d",&a[i].l,&a[i].r);
	sort(a+1,a+m+1);
	if(a[1].l>1){
		printf("-1\n");
		return 0;
	}
	int s=1,e=1,sum=1;
	for(int i=1;i<=m;i++){
		if(a[i].l<=s)//有多个区间与当前区间重合,找到终点最大的区间. 
			e=max(e,a[i].r);
		else{//如果没有此时没有了重合的区间,就去更新当前区间,继续寻找下一个区间. 
			sum++;
			s=e+1;//未更新过的区间的终点 
			if(a[i].l<=s)	e=max(e,a[i].r);//要选择的下一个区间最右边的点. 
			else{
				printf("-1\n");//没有符合条件的就出现了断层
				return 0;
			}	
		}
		if(e>=n) break;
	} 
	printf("%d\n",e>=n?sum:-1);
	return 0;
}

华华教月月做数学(Java大数,快速幂+快速乘模板)

?题目地址:https://ac.nowcoder.com/acm/contest/392/B ?

java大数无敌,很方便.函数用好就ok.

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int T = in.nextInt();
        while(T-->0){
            BigInteger a = in.nextBigInteger();
            BigInteger b = in.nextBigInteger();
            BigInteger mod = in.nextBigInteger();
            BigInteger ans = a.modPow(b,mod);
            System.out.println(ans);
        }
    }
}

处理高精度使用快速幂+快速乘

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int Max_n=100005;
typedef long long LL;

LL q_mul(LL a,LL b,LL mod){//快速乘
	LL ans=0,res=a;
	while(b){
		if(b&1) ans=(ans+res)%mod;
		res=(res+res)%mod;
		b>>=1;
	}
	return ans;
}

LL q_pow(LL a,LL b,LL mod){//快速幂
	LL ans=1,res=a;
	while(b){
		if(b&1) ans=q_mul(ans,res,mod);
		res=q_mul(res,res,mod);
		b>>=1;
	}
	return ans;	
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		LL a,b,mod;
		scanf("%lld%lld%lld",&a,&b,&mod);
		LL ans=q_pow(a,b,mod);
		printf("%lld\n",ans);
	}
	return 0;
}

华华给月月出题(线性筛法,快速幂)

?题目地址:https://ac.nowcoder.com/acm/contest/392/C ?
?积性函数:https://baike.baidu.com/item/积性函数/8354949?fr=aladdin ?
?线性筛法:https://blog.youkuaiyun.com/qq_42217376/article/details/88418482 ?
如题:xn就是一个积性函数,再加上线性筛即可解决此问题
这个题,我所有的数据类型都用的LL一直内存超限,后来改成了int过了,原因不详.

#include<cstdio>
#include<iostream>
#include<vector>
#define mod 1000000007
using namespace std;
 
const int Max_n=13000010;
typedef long long LL;
int f[Max_n],n;
bool is_prime[Max_n];
vector<int>prime;
 
int q_pow(int a,int b){
    int ans=1,res=a;
    while(b){
        if(b&1) ans=(1LL*ans*res)%mod;
        res=(1LL*res*res)%mod;
        b>>=1;
    }
    return ans;
}
  
int main(){
    scanf("%d",&n);
    LL ans=0;
    for(int i=2;i<=n;i++) is_prime[i]=true;
    for(int i=2;i<=n;i++){
        if(is_prime[i]){
            prime.push_back(i);
            f[i]=q_pow(i,n);
        }
        for(int j=1;j<(int)prime.size();j++){
            if(i*prime[j]>n) break;
            is_prime[i*prime[j]]=false;
            f[i*prime[j]]=(1LL*f[i]*f[prime[j]])%mod;//保证每个数只被计算一次
            if(i%prime[j]==0) break;
        }
        ans^=f[i];
    }
    printf("%lld\n",ans^1);
    return 0;
}


华华给月月准备礼物(二分)

?题目地址:https://ac.nowcoder.com/acm/contest/392/E ?
直接二分棍子的长度,然后找到最长的即可.

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int Max_n=100005;
typedef long long LL;
int a[Max_n],n,k;


bool check(int mid){
	int cnt=0,flag=false;
	for(int i=1;i<=n;i++){
		cnt+=a[i]/mid;
		if(cnt>=k){//能够分解成k根 
			flag=true;
			break;
		} 
	}	
	return flag; 
} 

int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	int l=1,r=1000000000,ans=0;
	while(l<=r){//二分长度 
		int mid=l+(r-l)/2;
		if(check(mid)){//当前长度能够分解成k根,长度还可以增加.
			l=mid+1;
			ans=mid; 
		}else{
			r=mid-1;
		}
	}
	printf("%d\n",ans);
	return 0;
}

华华开始学信息学(树状数组)

?题目地址:https://ac.nowcoder.com/acm/contest/392/F ?

?实在看不懂题解说的上限,看着别人写(代码+思路)的模仿着敲了两遍,改了n多遍,结果一直只过10%的数据.最后还是放弃,直接树状数组暴力过90%的数据.下面贴出来树状数组模板.

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;

typedef long long LL;
const int Max_n=100005;
LL d[Max_n];
int n,m;

void add(int x,int v){//单点修改
    while(x<=n){
        d[x]+=v;
        x+=(x&-x);
    }
}

LL quary(int x){//计算前缀和
    LL ans=0;
    while(x){
        ans+=d[x];
        x-=(x&-x);
    }
    return ans;
}

int main() {
    scanf("%d%d",&n,&m);
    while(m--){
        int opt,l,r;
        scanf("%d%d%d",&opt,&l,&r);
        if(opt==1){
            for(int i=l;i<=n;i+=l)
                add(i,r);
        }else{
            LL ans=quary(r)-quary(l-1);
            printf("%lld\n",ans);
        }
    }
    return 0;
}
    

华华对月月的忠诚(最大公约数)

?题目地址:https://ac.nowcoder.com/acm/contest/392/G ?
?比赛的时候把gcd函数写错.......

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int Max_n=100005;
typedef long long LL;
char s[Max_n];

LL gcd(LL a,LL b){
	if(a<b){LL t=a;a=b;b=t;}
	return b==0?a:gcd(b,a%b);
}

int main(){
	LL a,b;
	scanf("%lld%lld",&a,&b);
	scanf("%s",s);
	LL ans=gcd(a,b);
	printf("%lld\n",ans);
	return 0;
}

华华和月月逛公园(tarjan算法)

?题目地址:https://ac.nowcoder.com/acm/contest/392/I ?


月月查华华的手机(STL专题之string的应用)

?题目地址:https://ac.nowcoder.com/acm/contest/392/J ?
string中find的神奇应用,不过不知道为什么1012没有超时.应该还有其他解法.

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

const int Max_n=100005;
typedef long long LL;

int main(){
	string a;
	int n;
	cin>>a>>n;
	getchar();
	while(n--){
		string b;
		cin>>b;
		bool flag=true;
		int len=b.length();
		size_t index=a.find(b[0]);//先找到第一个位置.
		if(index==a.npos){
			cout<<"No"<<endl;
			continue;
		}
		for(int i=1;i<len;i++){
			index=a.find(b[i],index+1);
			if(index==a.npos){
				flag=false;
				break;
			}
		}
		if(flag) cout<<"Yes"<<endl;
		else cout<<"No"<<endl; 
	}
	return 0;
}

### 关于牛客小白109的信息 目前并未找到关于牛客小白109的具体比信息或题解内容[^5]。然而,可以推测该事可能属于牛客网举办的系列算法竞之一,通常这类比会涉及数据结构、动态规划、图论等经典算法问题。 如果要准备类似的事,可以通过分析其他场次的比题目来提升自己的能力。例如,在牛客小白13中,有一道与二叉树相关的题目,其核心在于处理树的操作以及统计最终的结果[^3]。通过研究此类问题的解决方法,能够帮助理解如何高效地设计算法并优化时间复杂度。 以下是基于已有经验的一个通用解决方案框架用于应对类似场景下的批量更新操作: ```python class TreeNode: def __init__(self, id): self.id = id self.weight = 0 self.children = [] def build_tree(n): nodes = [TreeNode(i) for i in range(1, n + 1)] for node in nodes: if 2 * node.id <= n: node.children.append(nodes[2 * node.id - 1]) if 2 * node.id + 1 <= n: node.children.append(nodes[2 * node.id]) return nodes[0] def apply_operations(root, operations, m): from collections import defaultdict counts = defaultdict(int) def update_subtree(node, delta): stack = [node] while stack: current = stack.pop() current.weight += delta counts[current.weight] += 1 for child in current.children: stack.append(child) def exclude_subtree(node, total_nodes, delta): nonlocal root stack = [(root, False)] # (current_node, visited) subtree_size = set() while stack: current, visited = stack.pop() if not visited and current != node: stack.append((current, True)) for child in current.children: stack.append((child, False)) elif visited or current == node: if current != node: subtree_size.add(current.id) all_ids = {i for i in range(1, total_nodes + 1)} outside_ids = all_ids.difference(subtree_size.union({node.id})) for idx in outside_ids: nodes[idx].weight += delta counts[nodes[idx].weight] += 1 global nodes nodes = {} queue = [root] while queue: curr = queue.pop(0) nodes[curr.id] = curr for c in curr.children: queue.append(c) for operation in operations: op_type, x = operation.split(' ') x = int(x) target_node = nodes.get(x, None) if not target_node: continue if op_type == '1': update_subtree(target_node, 1) elif op_type == '2' and target_node is not None: exclude_subtree(target_node, n, 1) elif op_type == '3': path_to_root = [] temp = target_node while temp: path_to_root.append(temp) if temp.id % 2 == 0: parent_id = temp.id // 2 else: parent_id = (temp.id - 1) // 2 if parent_id >= 1: temp = nodes[parent_id] else: break for p in path_to_root: p.weight += 1 counts[p.weight] += 1 elif op_type == '4': pass # Implement similarly to other cases. result = [counts[i] for i in range(m + 1)] return result ``` 上述代码片段展示了针对特定类型的树形结构及其操作的一种实现方式。尽管它并非直接对应小白109中的具体题目,但它提供了一个可借鉴的设计思路。 ####
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值