首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >牛客2025秋季算法编程训练联赛4-基础组

牛客2025秋季算法编程训练联赛4-基础组

作者头像
用户11956880
发布2025-12-18 18:23:08
发布2025-12-18 18:23:08
80
举报

A 欧几里得

题目描述

欧几里得算法是一种求最大公约数的有效算法,在算法竞赛中很常用。

这个算法的 Python 实现如下:

代码语言:javascript
复制
def gcd(a,b):
    if b == 0:
        return a
    return gcd(b,a%b)

现在,如果已知 gcd(a,b) 共递归了 n次,求所有可能的a,b中满足a>b>=0且a+b最小的一组的a与b之和。

输入描述:

第一行一个整数,T。

接下来T行一行一个整数,n。

输出描述:

T行,每行一个整数,代表a+b。

示例1

输入

复制1 0

代码语言:javascript
复制
1
0

输出

复制1

代码语言:javascript
复制
1

说明

代码语言:javascript
复制
gcd(1,0) 由于 b=0,不会递归,即是递归0次。

示例2

输入

复制1 1

代码语言:javascript
复制
1
1

输出

复制3

代码语言:javascript
复制
3

说明

代码语言:javascript
复制
gcd(2,1)会递归一次至gcd(1,0)。

备注:

1≤T≤81 0≤n≤800≤n≤80

思路列出几个数就可以发现规律,类似于斐波那契博弈的递推

代码语言:javascript
复制
#include<bits/stdc++.h>
using namespace std;
#define int long long
int ans=INT_MAX;
pair<int,int>a[100];
signed main(){
	int t,n;
	cin>>t;
	while(t--){
		cin>>n;
		a[0].first=1,a[0].second=0;
		a[1].first=2,a[1].second=1;
		for(int i=2;i<=100;i++){
			a[i].first=a[i-1].first+a[i-1].second;
			a[i].second=a[i-1].first;
		}
		cout<<a[n].first+a[n].second<<endl;
	}
	//gcd(a,b);
} 

B 括号序列

题目描述

注意:数据已加强并进行了rejudge

给出一个仅包含'[',']','(',')','{','}'六种字符的括号序列,判断其是否合法。

  • 空串是一个合法的括号序列
  • 如果A, B 都是合法的括号序列,那么AB也是合法的括号序列
  • 如果A是合法的括号序列,(A) , [A], {A}都是合法的括号序列

输入描述:

代码语言:javascript
复制
一行一个字符串S,只包含题目中的六种括号字符

输出描述:

代码语言:javascript
复制
输出为一行"Yes" 或"No"

示例1

输入

复制(){}[]

代码语言:javascript
复制
(){}[]

输出

复制Yes

代码语言:javascript
复制
Yes

示例2

输入

复制({[]})

代码语言:javascript
复制
({[]})

输出

复制Yes

代码语言:javascript
复制
Yes

示例3

输入

复制([)]

代码语言:javascript
复制
([)]

输出

复制No

代码语言:javascript
复制
No

备注:

代码语言:javascript
复制
1≤∣S∣≤1000000

利用栈,遇到左括号就给压进去,遇到有括号就开始进行匹配

代码语言:javascript
复制
#include<bits/stdc++.h>
using namespace std;
string s;
stack<char>stk;
bool f(){
	for(char c:s){
		if(c=='('||c=='{'||c=='['){
			stk.push(c);
		}
		else{
			if(stk.empty()){
				return false;
			}
			else{
				char top=stk.top();
				if((c==')'&&top=='(')||
				   (c=='}'&&top=='{')||
				   (c==']'&&top=='[')){
				   	stk.pop();
				}
				else{
					return false;
				}
			}
		}
	}
	return stk.empty();
}
int main(){
	getline(cin, s);
	if(f()){
		cout<<"Yes";
	}
	else{
		cout<<"No";
	}
	
}

C 子段乘积

题目描述

给出一个长度为 n 的数列 a1,a2,…,ana_1,a_2,\ldots,a_na1​,a2​,…,an​,求其长度为 k 的连续子段的乘积对 998244353 取模余数的最大值。

输入描述:

代码语言:javascript
复制
第一行两个整数n,k。
第二行n个整数,a1,a2,…,ana_1,a_2,\ldots,a_na1​,a2​,…,an​。

输出描述:

代码语言:javascript
复制
输出一个整数,代表最大余数。

示例1

输入

复制5 3 1 2 3 0 8

代码语言:javascript
复制
5 3
1 2 3 0 8

输出

复制6

代码语言:javascript
复制
6

说明

代码语言:javascript
复制
1∗2∗3mod  998244353=61*2*3\mod 998244353=61∗2∗3mod998244353=6

备注:

1≤k≤n≤2∗105

0≤ai<9982443530 \le a_i <9982443530≤ai​<998244353

思路

利用逆元,除法同余原理,滑动窗口,进行操作

代码语言:javascript
复制
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int a[200030];
int power(int b,int n) {
    int ans=1;
    while(n>0) {
        if((n&1)==1) {
            ans=(ans*b)%mod;
        }
        b=(b*b)%mod;
        n>>=1;
    }
    return ans;
}
signed main() {
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++) {
        cin>>a[i];
    }
    if(k==0){
        cout<<1<<endl;
        return 0;
    }
    int ans=1;
    int zero_count=0;
    for(int i=1;i<=k;i++) {
        if(a[i]==0)zero_count++;
        else ans=(ans*a[i])%mod;
    }
    int res=(zero_count==0)?ans:0;
    for(int i=k+1;i<=n;i++){
        if(a[i-k]==0) zero_count--;
        else{
            ans=(ans*power(a[i-k],mod-2))%mod;
        }
        if(a[i]==0) zero_count++;
        else ans=(ans*a[i])%mod;
        if(zero_count==0){
            res=max(res,ans);
        }else{ 
            res=max(res,0LL);
        }
    }
    cout <<res%mod<<endl;
    return 0;
}

D 子段异或

题目描述

输入一个数列a,你需要输出其中异或值为0的不同子段的数量。一个子段 [l,r] (1≤l≤r≤n1 \le l \le r \le n1≤l≤r≤n)的异或值为al⊕al+1⊕al+2⊕…⊕ara_l \oplus a_{l+1} \oplus a_{l+2} \oplus \ldots\oplus a_ral​⊕al+1​⊕al+2​⊕…⊕ar​,其中⊕\oplus⊕符号代表异或运算

两个子段被视为相同的,当且仅当其开始和结束位置均对应相同。

输入描述:

第一行一个整数 n ,代表数列长度。

第二行 n 个整数,代表数列。

输出描述:

代码语言:javascript
复制
输出一个整数,代表答案。

示例1

输入

复制5 1 2 3 2 1

代码语言:javascript
复制
5
1 2 3 2 1

输出

复制2

代码语言:javascript
复制
2

说明

代码语言:javascript
复制
子段 [1,3] 和子段 [3,5] 是合法子段。

备注:

代码语言:javascript
复制
n≤200000,0≤ai​≤2^30−1

思路 找到prefix[l-1] 与prefix[r]相等,这俩异或肯定为0,然后prefix[r]一定也包括prefix[l-1]所以就可以知道l到r一定异或值为0

代码语言:javascript
复制
#include<bits/stdc++.h>
using namespace std;
long long prefix;
int a[200020];
int main(){
    int n;
    cin>>n;
    unordered_map<long long ,long long>mp;
    mp[0]=1;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        prefix^=a[i];
        mp[prefix]++;
    }
    long long ans=0;
    for(auto &p : mp){
        long long c=p.second;
        ans+=c*(c-1)/2;
    }
    cout<<ans;
    
    
}

E 最小表达式

题目描述

给出一个包含数字1-9和加号的字符串,请你将字符串中的字符任意排列,但每种字符数目不变,使得结果是一个合法的表达式,而且表达式的值最小。输出那个最小表达式的值

合法的表达式的定义如下:

- 一个数字,如233,是一个合法的表达式

- A + B是合法的表达式,当且仅当 A , B 都是合法的表达式

保证给出的表达式经过重排,存在一个合法的解。

输入描述:

一行输入一个字符串,仅包含数字1-9和加号+。

字符串的长度小于5∗1055*10^55∗105。

输出描述:

代码语言:javascript
复制
一行输出一个数字,代表最小的解。

示例1

输入

复制111+1

代码语言:javascript
复制
111+1

输出

复制22

代码语言:javascript
复制
22

说明

代码语言:javascript
复制
11+11=22

示例2

输入

复制9998765432111

代码语言:javascript
复制
9998765432111

输出

复制1112345678999

代码语言:javascript
复制
1112345678999

示例3

输入

复制12+35

代码语言:javascript
复制
12+35

输出

复制38

代码语言:javascript
复制
38

说明

25+13 = 38

示例4

输入

复制23984692+238752+2+34+

代码语言:javascript
复制
23984692+238752+2+34+

输出

复制5461

代码语言:javascript
复制
5461

说明

嗯,这个答案是可以得到的

备注:

代码语言:javascript
复制
注意,答案长度可能长达500000个字符。

思路

就是利用贪心加高精度,其实就是看一下+有几个然后分成几组数,然后把最小的数字都扔给最高位,再利用高精度相加

代码语言:javascript
复制
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500010;
int res[MAXN];
int main() {
    string s;
    cin>>s;
    vector<char>digits;
    int k=0;
    for(char c:s) {
        if(c=='+'){
            k++;
        }
		else{
            digits.push_back(c);
        }
    }
    sort(digits.begin(),digits.end());
    int n=digits.size();
    int m=k+1;
    int len=n/m;
    int r=n%m;
    int start=0;
    if(r>0){//有r组数需要多一位数 
        int S1=0;
        for(int i=0;i<r;i++){
            S1+=digits[start++]-'0';
        }
        res[len]+=S1;//所以从len开始 
    }
    for(int j=len-1;j>=0;j--){
        int S=0;
        for(int i=0;i<m;i++) {//先把最小的数给最高位,所以从len-1开始 
            S+=digits[start++]-'0';
        }
        res[j]+=S;
    }
    int L=len+10;//防止进位时候越界 
    for (int i=0;i<L-1;i++) {
        if(res[i]>=10){
            res[i+1]+=res[i]/10;
            res[i]%=10;
        }
    }
    int high=L-1;
    while(high>0&&res[high]==0){
        high--;
    }
    for(int i=high;i>=0;i--){
        cout<<res[i];
    }
    cout<<endl;
    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • A 欧几里得
  • B 括号序列
  • C 子段乘积
  • D 子段异或
  • E 最小表达式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档