练习-day2

1.括号序列

链接:https://ac.nowcoder.com/acm/contest/120455/B

题目描述

合法括号序列的定义是:

1.空序列是合法括号序列

2.如果 S 是一个合法括号序列,那么(S)是合法括号序列

3.如果 A 和 B 都是合法括号序列,那么 AB 是一个合法括号序列

现在给定一个括号序列,求最少删去几个括号能得到一个合法的括号序列

输入包含 T 组数据,每组数据中,设括号序列的长度为 N

1≤T,ΣN≤1,000,000

(由于空串是合法的括号序列,所以答案可以是N)

输入描述:

第一行一个数字 T

接下来 T 组数据共 2T 行,每组数据第一行是 N

第二行则是一个长度为 N 的括号序列

输出描述:

T 行 T 个数字,表示输入的括号序列最少删去几个括号能得到一个合法的括号序列

输入

2

6

())(()

9

()(()()))

输出

2

1

思路

问删几个括号能得到一个合法的括号序列,括号""( ""就扔进去然后遇到" )"就看栈里面有能匹配的不,有的话就弹出来栈顶元素,没的话,这就是要删掉的括号,就ans++,然后当循环结束就看栈里面还有多少元素,然后让其和ans相加就行

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
    int t;
    cin>>t;
    while(t--){
        stack<int>st;
        int n;
        cin>>n;
        string s;
        cin>>s;
        int ans=0;
        for(int i=0;i<s.size();i++){
            if(s[i]=='('){
                st.push(s[i]);
            }
            else{
                if(st.empty()){
                    ans++;
                }
                else{
                        st.pop();
                }
            }
        }
        cout<<ans+st.size()<<endl;
    }
}

2.十字阵列

链接:https://ac.nowcoder.com/acm/contest/120455/C

来源:牛客网

题目描述

小 Q 新学会了一种魔法,可以对一个 N行M列 的网格上的敌人造成伤害

第 i 次使用魔法可以对网格上的一个十字形区域(即第 xi 行和第 yi 列的并)中的每个格子上的敌人造成 zi 点伤害

现在小 Q 一共使用了 H 次魔法,你需要在所有的施法完成之后统计造成伤害的情况,详见输出描述

提醒:本题输入规模较大,请使用高效的输入方式

1≤H≤500,000 1≤xi,yi,zi,N,M≤2000 1≤xi≤N,1≤yi≤M

输入描述:

第一行 3 个数字 N,M,H

接下来 H 行,每行 3 个正整数 xi,yi,zi

输出描述:

为了避免大量的输出,假设第 i 行第 j 列受到的总伤害是 wij

你只需要输出Σwij(i+j)对 10^9+7 取模的结果即可

输入

5 5 5
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5

输出

890

说明

造成伤害的情况是:

1 3 4 5 6

3 2 5 6 7

4 5 3 7 8

5 6 7 4 9

6 7 8 9 5

补充的说明:

890 = 1*(1+1)+3*(1+2)+4*(1+3)+...+5*(5+5),一共25项累加得到890

思路

根据题目描述,我们需要计算所有网格点 (i, j) 的伤害值 w_ij 乘以 (i+j) 的总和,即 Σ[w_ij * (i+j)]。直接使用两个循环遍历所有网格点计算会导致时间复杂度为 O(n*m),在 n 和 m 可能很大的情况下(如达到 10^5 级别)是不可行的。

所以我们用别的方法

  1. 预处理操作:读取每个操作 (x, y, z),并累加:

    • a[x]:第 x 行所有操作的总伤害

    • b[y]:第 y 列所有操作的总伤害

    • S:所有操作的总伤害之和

  2. 计算加权和

    • sumi:所有行的索引 i 与对应行总伤害 a[i] 的乘积之和

    • sumj:所有列的索引 j 与对应列总伤害 b[j] 的乘积之和

  3. 组合结果:使用公式:ans = ((m-1)*sumi + (n-1)*sumj + S*(T_m + T_n)) % mod

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int a[2020],b[2020];
const int mod=1e9+7;

signed main() {
    int n,m,h;
    cin>>n>>m>>h;
    int S=0;
    while(h--){
		int x,y,z;
		cin>>x>>y>>z;
		a[x]=(a[x]+z)%mod;
		b[y]=(b[y]+z)%mod;
		S=(S+z)%mod;
	}
	int sumi=0;
	for(int i=1;i<=n;i++){
		sumi=(sumi+i*a[i])%mod;
	}
	int sumj=0;
	for(int i=1;i<=m;i++){
		sumj=(sumj+i*b[i])%mod;
	}
	int ans=((m-1)*sumi%mod+(n-1)*sumj%mod+S*((m*(m+1)/2%mod+n*(n+1)/2%mod)%mod)%mod)%mod;
	cout<<ans;
    return 0;
}

3.配对

链接:https://ac.nowcoder.com/acm/contest/120455/D

题目描述

现在有正整数集合 A 和 B,每个集合里有 N 个数,你要建立他们间的一一映射

将每对配对的数字相加可以得到 N 个和,你要做的就是最大化第 K 大的和

1≤K≤N≤100,000 输入的所有数字不超过 108

输入描述:

第一行 2 个数字 N,K

接下来两行,每行 N 个正整数,分别表示 A 和 B 中的元素

输出描述:

一行,表示第 K 大的和的最大值

示例1

输入

3 2 1 2 3 1 2 3

复制代码
3 2
1 2 3
1 2 3

输出

5

5

思路

  1. 排序策略

    • A 和 B 都按升序排序

    • 外层循环 j 从 B 的最大值开始向前遍历(从大到小)

    • 内层循环 i 从 A 的最小值开始向后遍历(从小到大)

  2. 贪心匹配逻辑

    • 对于每个 B[j](从大到小),我们尝试找到最小的 A[i] 使得 A[i] + B[j] ≥ x

    • while (i < n && A[i] + B[j] < x) 的意思是:

      • 如果当前的 A[i] 太小,无法与 B[j] 配对达到 x,就跳过它

      • 继续检查下一个更大的 A[i]

    • 一旦找到满足条件的 A[i],就计数并标记该 A[i] 已被使用、

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int n, k;
vector<int> A, B;

bool check(int x) {
    int count = 0;
    int i = 0;
    for (int j = n - 1; j >= 0; j--) {
        while (i < n && A[i] + B[j] < x) {
            i++;
        }
        if (i < n) {
            count++;
            i++;
        }
    }
    return count >= k;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n >> k;
    A.resize(n);
    B.resize(n);
    for (int i = 0; i < n; i++) {
        cin >> A[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> B[i];
    }
    
    sort(A.begin(), A.end());
    sort(B.begin(), B.end());
    
    int left = 1, right = 200000001;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (check(mid)) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    cout << left - 1 << endl;
    
    return 0;
}

4.无穷无尽的字符串

链接:https://ac.nowcoder.com/acm/contest/123788/B

题目描述

\hspace{15pt}小红有无穷无尽的字符串。

\hspace{15pt}小红拿到了一个由无限个 abc\texttt{abc}abc 依次拼接而成的字符串 abcabcabc...\texttt{abcabcabc}\dotsabcabcabc...,她想知道从字符串的第 lll 位到第 rrr 位中,a,b,ca,b,ca,b,c 分别出现了多少次,请你帮帮她。

输入描述:

第一行输入两个整数

𝑙,𝑟(1≦𝑙≦𝑟≦10^9)l,r(1≦l≦r≦10^9 )。

输出描述:

复制代码
输出三个整数,分别代表 a,b,ca,b,ca,b,c 出现的次数。

示例1

输入

复制1 3

复制代码
1 3

输出

复制1 1 1

复制代码
1 1 1

思路

字符串是无限重复的"abc",每个位置pos(从1开始)的字符规则是:

pos mod 3 = 1 → 'a'

pos mod 3 = 2 → 'b'

pos mod 3 = 0 → 'c'

对于任意整数 n,在 1n 的范围内:

  • 模3余0的数的个数:n/3

  • 模3余1的数的个数:(n+2)/3

  • 模3余2的数的个数:(n+1)/3

    cpp 复制代码
    #include <iostream>
    using namespace std;
    int l;
    int r;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
         cin>>l>>r;
    	    l--;
    	    for(int i=2;i>=0;i--){
    	        cout<<(r+i)/3-(l+i)/3<<' ';
    	    }
        return 0;
    }

5.米斯蒂娅不想被吃掉

链接:https://ac.nowcoder.com/acm/contest/124143/B

题目描述

链接:https://ac.nowcoder.com/acm/contest/124143/B

来源:牛客网

米斯蒂娅经常去摆烧烤摊,幽幽子是烧烤摊的常客。

幽幽子每天都要吃 x 吨烧烤才会满意,在 n 天内米斯蒂娅每天会拿到若干吨食材,她可以将其中一部分做成烧烤,但食材最多只能存放 2 天(也就是说只能用当天或者前一天的食材做烧烤)。如果某天幽幽子不满意就会把米斯蒂娅吃掉。米斯蒂娅想知道是否存在一种烧烤策略,使得自己在 𝑛 天内不会被吃掉,请你帮帮她。

我们假设食材做成烧烤的过程是没有重量变化的。

输入描述:

每个测试文件均包含多组测试数据。第一行输入一个整数 𝑇 (1≦𝑇≦10)T (1≦T≦10) 代表数据组数,每组测试数据描述如下:第一行输入两个整数𝑛,𝑥(1≦𝑛≦2×105,1≦𝑥≦2×105)n,x(1≦n≦2×10^5,1≦x≦2×10^5 )。第二行输入n 个整 数 𝑎𝑖(0≦𝑎𝑖≦2×10^5)a i(0≦a i ≦2×10^5 ),代表第𝑖天拿到的食材吨数。

输出描述:

复制代码
对于每组测试数据,新起一行。如果存在一种策略使得米斯蒂娅不会被吃掉,请输出 Yes;否则输出 No。

输入

2

3 1

2 0 1

3 2

6 0 1

输出

Yes

No

说明

对于第一组数据,米斯蒂娅可以每天都做一吨烧烤。

对于第二组数据,第三天一定无法做出两吨烧烤。

思路:比较简单哈,需要注意到是别遇到No的情况就直接return了,必须要让人家给输入完,要不然就报错

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
void solve(){
	int n,x;
	cin >> n >> x;
	int per = 0,flag = 0;
	for(int i = 1;i <= n;i ++){
        int t;
		cin >> t;
		if(t + per < x){
			flag = 1;
//             break;
		}
//         per
		if(per >= x){
			per = t;
		}else{
			per = t - (x - per);
		}
	}
    if(flag == 0)
	cout << "Yes"<<endl;
    else cout <<"No\n";
    return;
}
int main(){
	int T;
    cin >> T;
	while(T --){
		solve();
	}
	return 0;
} 
相关推荐
monster000w19 小时前
大模型微调过程
人工智能·深度学习·算法·计算机视觉·信息与通信
小小晓.19 小时前
Pinely Round 4 (Div. 1 + Div. 2)
c++·算法
SHOJYS19 小时前
学习离线处理 [CSP-J 2022 山东] 部署
数据结构·c++·学习·算法
biter down19 小时前
c++:两种建堆方式的时间复杂度深度解析
算法
zhishidi19 小时前
推荐算法优缺点及通俗解读
算法·机器学习·推荐算法
WineMonk19 小时前
WPF 力导引算法实现图布局
算法·wpf
2401_8370885020 小时前
双端队列(Deque)
算法
ada7_20 小时前
LeetCode(python)108.将有序数组转换为二叉搜索树
数据结构·python·算法·leetcode
奥特曼_ it20 小时前
【机器学习】python旅游数据分析可视化协同过滤算法推荐系统(完整系统源码+数据库+开发笔记+详细部署教程)✅
python·算法·机器学习·数据分析·django·毕业设计·旅游
仰泳的熊猫20 小时前
1084 Broken Keyboard
数据结构·c++·算法·pat考试