826某团笔试

第一题

小美手机上种果树,只要成熟了就可以得到免费的水果了。

小美每天可以给果树浇水,果树成长值为下x,同时可一个给果树施肥,两次施肥至少间隔2天,果树的成长值加y,果树的成长值达到z就成熟了

小红想知道,最少需要多少天就可以领到免费的水果

输入描述:
一行三个整数x, y, z,分别表示浇水的成长值,果树成熟的成长值。
1≤x,y,z≤10^9

输出描述
一行一个整数,表示最少需要的多少天可以领到免费的水果。

示例1
输入:
1 2 10
输出:
6

第一天施肥浇水,成长值为3。
第二天浇水。或长值为3+1=4。
第三天浇水。成长值为4+1=5.
第四天施肥浇水,成长值为5+3= 8。
第五天浇水。或长值为8+1= 9。
第六天浇水。成长值为9+1= 10。
果树成熟了,可以须到免费水果了!

公式

#include <iostream>

int main() {
    
    
    int value1, value2, value3;
    std::cin >> value1 >> value2 >> value3;

    int date = 0;
    while (date <= value3) {
    
    
        if (date * value1 + date / 3 * value2 == value3) {
    
    
            std::cout << date << std::endl;
            break;
        }
        date++;
    }
	std::cout << date << endl;
    return 0;
}

第二题

大家一起吃饭的时候,总是小红先付钱,然后大家再把钱转给小红。

现在小红有n张账单,每张账单记录了有k个人一起吃饭,以及吃饭的消费 c,现在小红需要计算每个人需要转给小红多少钱。

由于大家都比较喜欢整数,所以大家每张账单会转给小红[c/k],[x] 表示对 x进行上取整。

输入描述:
第一行输入两个数 n,m(1≤n, m ≤ 10^5)表示账单数和除小红外的总人数(分别用1到 m 示)

换下来 2 乘 n 行,每 2 行表示一张账单,对于每张账单:

第一行输入两个整数k(2≤k≤m+1),c(1≤c≤10^9)表示一起吃的人数,花费。

第二行输入k一1个整数,表示除小红外有哪些人一起吃饭。

输出描述:输出 m个整数,表示每个人要给小红转账的总金额

示例1
输入
2 3
3 10
1 2
4 8
1 2 3

输出: 6 6 2

说明
第一张账单:第1、2个人都会给小红转4元
第二张账单: 第1、2、3个人都会给小红转2元
因此答案为4+2=6,4+2=6,2

#include <iostream>
#include <vector>
#include <cmath>
#include <map>

using namespace std;

struct Data {
    
    
    int b;
    int c;
};

int main() {
    
    
    int n, m;
    cin >> n >> m;

    map<int, int> personToIndex; // 用于存储人员与索引的对应关系
    vector<int> amounts(m, 0); // 初始化每个人的总金额为0,索引从1开始
    vector<int,vector<int>> all_person(n,vector<int>(m,0));

    for (int i = 1; i <= m; ++i) {
    
    
        personToIndex[i] = i;
    }

    vector<Data> dataArr(n);

    for (int i = 0; i < n; ++i) {
    
    
        int k, c;
        cin >> k >> c;
        dataArr[i].b = k;
        dataArr[i].c = c;
        vector<int> person(k-1);
        for (int j = 0; j < k-1; j++) {
    
    
            cin >> person[j];
            int a = person[j];
            all_person[i][a-1] = 1;
        }
    }
    

    for (int i = 0; i < n; ++i) {
    
    

        int perPersonAmount =  dataArr[i].c / dataArr[i].b; // 每个人应该给小红转的金额
        int s =  dataArr[i].c % dataArr[i].b;
        if(s){
    
    
            perPersonAmount++;
        }

        for (int j = 0; j < m; j++) {
    
    
            if(all_person[i][j] == 1){
    
    
                amounts[j] += perPersonAmount; // 累加每个人需要转给小红的金额
            }
        }
    }

    // 输出每个人需要给小红转的总金额
    for (int i = 0; i <= m; ++i) {
    
    
        cout << amounts[i] << " ";
    }

    return 0;
}
#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

int main(){
    
    
	int n, m;
	cin >> n >> m;
	vector<long long>total_payment(m + 1, 0);
	for (int i = 0; i < n; i++) {
    
    
		int k, c;
		cin >> k >> c;
		total_payment_per_person = ceil(c * 1.0 / k);
		total_payment[0] += c - payment_per_person;

		for(int j = 0; j < k - 1; j++){
    
    
			int persion;
			cin >> persion;
			total_payment[persion] += payment_per_person;
		}
	}
	
	for (int i = 1; i <= m; i++){
    
    
		cout << total_payment[i] << " ";
	}
	
	return 0;
}

第三题

小美有两个长度为m的数组a和b

小美想知道,能不能通过重排a数组使得对于任意1≤i≤n,1≤a_i+b_i≤m将会有q次询问

输入描述:
第一行一个整数q(1≤q≤30),表示询问次数
对于每一个询问:
第一行输入两个整数n,m(1≤n,m≤500)
第二行输入n个正整数a_i(-500≤a_i≤500)
第三行输入n和正整数b_i(-500≤b_i≤500)

输出描述:
q行,每一行输出一个字符串,如果能通过重排满足条件就输出“Yes”,否则输出“No”

示例1:

输入
2
5 3
-1 -2 3 4 5
-1 3 4 2 5
5 6
-1 -2 3 4 5
-1 3 4 2 5

输出
No
Yes

说明
对于第一个用例,无论怎么排列都不满足条件
对于第二个用例,将数组a重排为[5,3,-2,4,-1]时满足条件。

这个问题的思路是这样的:

  • 首先,我们需要对a数组进行排序,使得它按照升序排列。这样,我们就可以保证a数组中最小的元素在最前面,最大的元素在最后面。
  • 然后,我们需要对b数组进行排序,但是按照降序排列。这样,我们就可以保证b数组中最大的元素在最前面,最小的元素在最后面。
  • 最后,我们需要遍历两个数组,同时比较它们对应位置的元素之和。如果对于任意1≤i≤n,1≤a_i+b_i≤m都成立,那么我们就可以通过重排a数组满足条件。否则,我们就不能满足条件。
  • 这个思路的原理是,如果我们想让a_i+b_i尽可能接近m,那么我们就需要让a_i尽可能大,b_i尽可能小。反之,如果我们想让a_i+b_i尽可能接近1,那么我们就需要让a_i尽可能小,b_i尽可能大。所以,通过排序两个数组,我们就可以实现这个目的。
  • 这个思路的时间复杂度是O(nlogn),因为我们需要对两个数组进行排序。空间复杂度是O(1),因为我们不需要额外的空间。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 判断是否能通过重排a数组使得对于任意1≤i≤n,1≤a_i+b_i≤m
bool can_rearrange(vector<int>& a, vector<int>& b, int m) {
    
    
  // 对a数组排序
  sort(a.begin(), a.end());
  // 对b数组排序,但是按照降序
  sort(b.begin(), b.end(), greater<int>());
  // 遍历两个数组,检查是否满足条件
  for (int i = 0; i < a.size(); i++) {
    
    
    // 如果a_i+b_i不在[1,m]范围内,返回false
    if (a[i] + b[i] < 1 || a[i] + b[i] > m) {
    
    
      return false;
    }
  }
  // 如果都满足条件,返回true
  return true;
}

int main() {
    
    
  // 输入询问次数
  int q;
  cin >> q;
  // 对于每一个询问
  while (q--) {
    
    
    // 输入n和m
    int n, m;
    cin >> n >> m;
    // 创建两个长度为n的数组a和b
    vector<int> a(n), b(n);
    // 输入a数组的元素
    for (int i = 0; i < n; i++) {
    
    
      cin >> a[i];
    }
    // 输入b数组的元素
    for (int i = 0; i < n; i++) {
    
    
      cin >> b[i];
    }
    // 调用函数判断是否能重排
    bool ans = can_rearrange(a, b, m);
    // 输出结果
    if (ans) {
    
    
      cout << "Yes" << endl;
    } else {
    
    
      cout << "No" << endl;
    }
  }
  return 0;
}

第四题

给定n个正整数组成的数组,求平均数正好等于k的最长连续子数组的长度

输入描述:
第一行输入两个正整数n和k;
第二行输入n个正整数a_i,来表示数组。
1 ≤ n ≤ 200000
1 ≤ k_i, a_i ≤ 10^9

输出描述
如果不存在任何一个连续子数组的平均数等于k,则输出-1。
否则输出平均数正好等于k的最长连续子数组的长度。

示例1
输入
5 2
1 3 2 4 1

输出
3

滑动窗口的思路是这样的:

  • 我们维护一个窗口,即一个连续的子数组,用两个变量left和right表示窗口的左右边界。
  • 我们不断地移动窗口的边界,使得窗口内的元素满足一定的条件,比如平均数等于k。
  • 我们用一个变量sum记录窗口内元素的和,这样我们可以在O(1)的时间内计算窗口内元素的平均数。
  • 我们从左到右遍历数组,每次将right指向的元素加入窗口,然后判断是否满足条件。
  • 如果满足条件,我们就更新结果为当前窗口的长度,并且尝试缩小窗口,看是否还能满足条件。
  • 如果不满足条件,我们就扩大窗口,直到满足条件或者right到达数组的末尾。
  • 这样,我们就可以找到所有满足条件的连续子数组,并且取其中最长的一个作为答案。

#include <iostream>
#include <vector>

using namespace std;

int maxSubarrayLengthWithAvgK(vector<int>& nums, int k) {
    
    
    int n = nums.size();
    int sum = 0, maxLength = -1;
    int left = 0, right = 0;

    // 使用双指针 left 和 right 维护一个滑动窗口
    while (right < n) {
    
    
        sum += nums[right];  // 将右指针对应的元素加入窗口总和

        // 当窗口总和大于期望平均值乘以窗口长度时,缩小窗口
        while (sum > k * (right - left + 1)) {
    
    
            sum -= nums[left];  // 将左指针对应的元素从窗口总和中减去
            left++;             // 左指针右移,缩小窗口
        }

        // 如果窗口总和等于期望平均值乘以窗口长度,更新最长子数组长度
        if (sum == k * (right - left + 1)) {
    
    
            maxLength = max(maxLength, right - left + 1);
        }

        right++;  // 右指针右移,扩大窗口
    }

    return maxLength;
}

int main() {
    
    
    int n, k;
    cin >> n >> k;

    vector<int> nums(n);
    for (int i = 0; i < n; ++i) {
    
    
        cin >> nums[i];
    }

    int result = maxSubarrayLengthWithAvgK(nums, k);
    cout << result << endl;

    return 0;
}

回溯思路,找出所有符号要求的连续子序列,求最大子序列长度

#include <iostream>
#include <vector>
using namespace std;

// 全局变量,存储结果
vector<vector<int>> ans;

// 回溯函数,找出所有连续子数组
void backtrack(vector<int>& a, int k, int start, int sum, vector<int>& path) {
    
    
  // 如果路径的长度大于0,判断是否满足条件
  if (path.size() > 0) {
    
    

    // 如果平均数等于k,将路径加入结果
    if (sum == k * path.size()) {
    
    
      ans.push_back(path);
    }
  }
  // 如果开始位置超过数组的长度,返回
  if (start >= a.size()) {
    
    
    return;
  }
  // 只考虑从开始位置开始的连续子数组,不需要遍历整个数组
  // 将当前元素加入路径
  path.push_back(a[start]);
  // 更新路径的和
  sum += a[start];
  // 递归调用回溯函数,从下一个位置开始
  backtrack(a, k, start + 1, sum, path);
  // 回溯,将当前元素移出路径
  path.pop_back();
  // 更新路径的和
  sum -= a[start];
}

// 求平均数正好等于k的所有连续子数组
vector<vector<int>> subarrays_with_avg(vector<int>& a, int k) {
    
    
  // 清空结果
  ans.clear();
  // 创建一个临时变量,存储当前路径
  vector<int> path;
  // 遍历数组,从每个位置开始调用回溯函数,初始和为0
  for (int i = 0; i < a.size(); i++) {
    
    
    backtrack(a, k, i, 0, path);
  }
  
  // 返回结果
  return ans;
}

// 找出结果中最长的数组的值
int longest_subarray_value(vector<vector<int>>& ans) {
    
    
  // 初始化结果为-1
  int res = -1;
  // 初始化最长的数组的长度为0
  int max_len = 0;
  // 遍历结果中的每个数组
  for (auto& sub : ans) {
    
    
    
    if (sub.size() > max_len) {
    
    
      res = sub.size();
      max_len = sub.size();
    }
  }
  // 返回结果
  return res;
}

int main() {
    
    
  // 输入n和k
  int n, k;
  cin >> n >> k;
  // 创建一个长度为n的数组a
  vector<int> a(n);
  // 输入a数组的元素
  for (int i = 0; i < n; i++) {
    
    
    cin >> a[i];
  }
  // 调用函数求解所有连续子数组
  vector<vector<int>> ans = subarrays_with_avg(a, k);
  
   // 调用函数求解最长子数组的值
   int res = longest_subarray_value(ans);

   // 输出结果
   cout << res << endl;

   return 0;
}

第五题

小美有一个长度为n的数组,她最多可以进行k次操作,每次操作如下:

  1. 选择两个整数i, j(1 ≤ i < j ≤ n)
  2. 选择两个整数x, y 使得x * y = a_i * a_j
  3. 将a_i替换为x,将a_i替换为y

她希望最多进行k次操作后,最后数组中的元素总和尽可能大。

输入描述
一行两个整数 n, k, 表述数组长度和操作的次数
一行n个整数a_1、a_2……a_n,表示数组的元素。
1 ≤ k < n ≤ 10^5
1 ≤ a_i ≤ 10^5

输出描述
输出一个整数,表示最后数组中的元素做那个和最大值,结果对10^9+7取模

示例1
输入
5 2
1 2 3 4 5

输出
65

说明
第一次操作后,数组变为[1, 2, 12, 1, 5]
第二次操作,数组变为[1, 2, 60, 1, 1]

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int mod = 1e9 + 7;

int main(){
    
    
    int n, k;
    cin >> n >> k;
    
    vector<int>nums(n);

    for(int i = 0; i < n; i++){
    
    
        cin >> nums[i];
    }

    sort(nums.begin(), nums.end(), greater<int>());
    
    int res = 1;
    for(int i = 0; i < n; i++){
    
    
        if(i <= k){
    
    
            res = res * nums[i];
        }
        else{
    
    
            res += nums[i];
        }
    }

    cout << res + k << endl;

    return 0;

}

猜你喜欢

转载自blog.csdn.net/weixin_47895938/article/details/132509768