刷题记录07-美团2024届秋招

1.小美的外卖订单

小美正在设计美团外卖的定价信息。已知外卖定价的规则如下:

  1. 每道菜有折扣价和原价。折扣价不能超过原价。
  2. 订单有满x元减y元的优惠。当购买的菜的价格总和不小于x元时,总价格可以减y元。“减”的价格不能超过“满”的价格。
  3. 满减优惠和折扣价是互斥的,当且仅当每个菜都选择了原价才可以触发满减。
  4. 系统会自动为客户计算最低价格的方案。
    在设计定价时,原价、折扣价和满减的价格都必须是正实数。如果设计的定价发生问题,则会提示数据错误。
    请使用等价划分法设计测试用例,来测试该系统的功能。

输入描述

第一行输入一个正整数n,代表菜的总数。
接下来的n行,每行输入两个实数a_i和b_i,代表每道菜的原价是a_i,折扣价是b_i。
最后一行输入两个实数x和y,代表满x元可以减y元。
数据中所有实数的绝对值不超过1000。

输出描述

如果数据有误,则输出一行字符串"error"。
否则输出一个小数,小数点后保留2位即可。该小数代表顾客购买了全部菜各一份时,订单的总价格。

示例

输入例子:
2
10 5.5
10 6.5
15 3
输出例子:
12.00
例子说明:
虽然触发了满15元减3元,但使用折扣只需要花12元,低于使用满减的价格(20-3=17),因此最终系统会为客户推荐折扣价。

输入例子:
2
10 5.5
10 6.5
20 10
输出例子:
10.00
例子说明:
触发满20元减10元即可。满减价优于折扣价。

输入例子:
2
10 10.25
10 3.5
20 4.5
输出例子:
error
例子说明:
折扣价高于原价,数据错误。

解题思路

刚看题的时候被吓住了,还以为可以又原价又折扣,一看是互斥的就变成了easy题了,但是特别恶心测试用例搞事情,要double才行,否则个10w个数据就放不下了,然后就是要注意非法输入错误处理。

代码

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

int main() {
	int n;   // n 道菜
	cin >> n;
	vector<double> prices(n);
	vector<double> discountprices(n);

	double sumo = 0;
	double sumdis = 0;

	for (int i = 0; i < n; ++i) {
		double discount;
		cin >> prices[i] >> discountprices[i];
		sumo += prices[i];
		sumdis += discountprices[i];
		if(discountprices[i] <= 0 ||  prices[i] <= 0 || discountprices[i] > prices[i]){
			cout << "error" << endl;
			return 0;
		}
	}
	double enough, sub;
	cin >> enough >> sub;
	if (sub <= 0 | enough <= 0 || sub > enough) {
		cout << "error" << endl;
		return 0;
	}
	if (sumo > enough) {
		sumo -= sub;
	}
	cout << fixed << setprecision(2) << min(sumo, sumdis) << endl;
}

2.小美的字符串匹配度

小美有两个长度为n只包含小写字母的字符串s和t,小美定义“两个字符串的匹配度”为i∈[1,n]中s i =t i​ 的数量,例如"abacd"和"aabdd"的匹配度就是2。现在你可以进行最多一次以下操作:对于字符串t,选择两个索引i,j(1≤i<j≤n),交换t i 和t j 。小美想知道,s和t的最大字符串匹配度是多少?

输入描述

第一行输入一个整数n
第二行输入一个长度为n的字符串s。
第三行输入一个长度为n的字符串t。

输出描述

输出一个整数,s和t的最大匹配度。

示例

输入例子:
5
ababc
babac
输出例子:
3

解题思路

先找一遍相等的,把不等的位置放到一个vector中,再到这个vector中遍历,看是否能交换到相等,或者交换后只让一个位置可以等也行。

代码

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

int main() {
    int n;
    cin >> n;
    string str1, str2;
    cin >> str1;
    cin >> str2;
    // 能交换就能加2,不能就不加
    bool change2 = false;
    bool change1 = false;
    int cnt = 0;
    vector<int> otherpos;
    for (int i = 0; i < n; ++i) {
        if (str1[i] == str2[i])
            cnt++;
        else {
            otherpos.push_back(i);
        }
    }

    for (int i : otherpos) {
        for (int j : otherpos) {
            if (i == j)
                continue;
            if (str1[i] == str2[j] && str1[j] == str2[i]) {
                change2 = true;
                break;
            }else if(str1[i] == str2[j]){
                change1 = true;
            }
        }
    }

    if (change2) {
        cnt += 2;
    }
    else if (change1) {
        cnt += 1;
    }

    cout << cnt << endl;
}

3.小美的树上染色

小美拿到了一棵树,每个节点有一个权值。初始每个节点都是白色。小美有若干次操作,每次操作可以选择两个相邻的节点,如果它们都是白色且权值的乘积是完全平方数,小美就可以把这两个节点同时染红。小美想知道,自己最多可以染红多少个节点?

输入描述

第一行输入一个正整数n,代表节点的数量。
第二行输入n个正整数a_i,代表每个节点的权值。
接下来的n-1行,每行输入两个正整数u,v,代表节点u和节点v有一条边连接。

输出描述

输出一个整数,表示最多可以染红的节点数量。

示例

输入例子:
3
3 3 12
1 2
2 3
输出例子:
2
例子说明:
可以染红第二个和第三个节点。
请注意,此时不能再染红第一个和第二个节点,因为第二个节点已经被染红。
因此,最多染红 2 个节点。

解题思路

想着构造出树出来,然后一个回溯,没写出来,求教。看大佬用拓扑排序做的,这段时间好好看一看。

代码

#define WHITE 1
#define RED 0
typedef int color;
struct treenode {
	color c;                      // 颜色
	treenode* parent;             // 父结点
	vector<treenode*> children;   // 子结点
	int value;                    // 权值
	treenode(int v) :value(v) { c = WHITE; };
};

bool isSqrt(int value) {
	int sq = sqrt(value);
	return sq == (value / sq);
}

int ret = -1;

void dfs(treenode* node, int& value) {
	// 怎么做啊怎么做
}

int main() {
	int n;                   // n个结点
	cin >> n;
	vector<treenode*> nodes(n+1);
	vector<int> values(n+1);
	for (int i = 1; i <= n; ++i) {
		cin >> values[i];
		treenode* node = new treenode(values[i]);
		nodes[i] = node;
	}

	nodes[1]->parent = nodes[0];
	nodes[0]->c = RED;

	for (int i = 1; i < n; ++i) {
		int p, c;
		cin >> p >> c;
		if (p > c)swap(p, c);
		nodes[c]->parent = nodes[p];
		nodes[p]->children.push_back(nodes[c]);
	}

	int value = 0;
	dfs(nodes[1], value);

	cout << ret << endl;

	return 0;
}

4.小美的排列询问

小美拿到了一个排列。她想知道在这个排列中,x和y是否是相邻的。你能帮帮她吗?排列是指一个长度为n的数组,其中 1 到n每个元素恰好出现一次。

输入描述

第一行输入一个正整数n,代表排列的长度。
第二行输入n个正整数a_i,代表排列的元素。
第三行输入两个正整数x和y,用空格隔开。

输出描述

如果x和y在排列中相邻,则输出"Yes"。否则输出"No"。

示例

输入例子:
4
1 4 2 3
2 4
输出例子:
Yes

输入例子:
5
3 4 5 1 2
3 2
输出例子:
No

解题思路

遍历一遍找左右。

代码

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

int main() {
	bool ret = false;
	int n;
	cin >> n;
	vector<int> nums(n);
	for (int i = 0; i < n; ++i) cin >> nums[i];
	int num1, num2;
	cin >> num1 >> num2;
	for (int i = 0; i < n; ++i) {
		if (nums[i] == num1) {
			if ( i>0 && nums[i-1] == num2) {
				ret = true;
			}
			if (i < n - 1 && nums[i + 1] == num2) {
				ret = true;
			}
		}
	}
	if (ret)
		cout << "Yes" << endl;
	else
		cout << "No" << endl;
}

5.小美的排列构造

小美定义一个数组
a的权值计算如下:
首先将a的每一对相邻两项求和,得到一个b数组。那么b数组的最大值减最小值即为a数组的权值。例如,若[2,1,3]a=[2,1,3],那么[3,4]b=[3,4],b数组的极差是1。因此a数组的权值为1。现在小美希望你能构造一个长度为n的排列,满足权值尽可能小。你能帮帮她吗?排列是指一个长度为n的数组,其中 1 到n每个元素恰好出现一次。

输入描述

一个正整数n,代表排列的长度。

输出描述

一个合法的排列。如果有多解输出任意即可。

示例

输入例子:
3
输出例子:
2 1 3
例子说明:
这个数组的权值为 1。输出[2,3,1]等排列也是合法的。

解题思路

妖法,把中间值(奇数)中间值后一个(偶数)放第一个,后面依次放这个值 减 位置值 / 2 向上取整。这样相邻的两数加和差就为 1 了。

代码

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

int main() {
    int n;
    cin >> n;
    vector<int> ret(n);

    int tmp = n / 2 + 1;
    int num;
    ret[0] = tmp;
    for (int i = 1; i < n; ++i) {
        if (i % 2 == 0) {
            num = i / 2;
            ret[i] = tmp + num;
        }
        else {
            num = i / 2 + 1;
            ret[i] = tmp - num;
        }
    }
    for (auto i : ret) cout << i << " ";
}

6.小美走公路

有一个环形的公路,上面共有n站,现在给定了顺时针第i站到第i+1站之间的距离(特殊的,也给出了第n站到第 1 站的距离)。小美想沿着公路第x站走到第y站,她想知道最短的距离是多少?

输入描述

第一行输入一个正整数n,代表站的数量。
第二行输入n个正整数a_i,前n-1个数代表顺时针沿着公路走,i站到第i+1站之间的距离;最后一个正整数代表顺时针沿着公路走,第n站到第 1 站的距离。·
第三行输入两个正整数x和y,代表小美的出发地和目的地。

输出描述

一个正整数,代表小美走的最短距离。

示例

输入例子:
3
1 2 2
2 3
输出例子:
2

输入例子:
3
1 2 2
1 3
输出例子:
2

解题思路

左边右边算了比较大小。注意要long。

代码

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

int main() {
	int n;
	cin >> n;
	vector<long> nums(n);
	for (int i = 0; i < n; ++i)cin >> nums[i];
	int a, b;
	cin >> a >> b;
	a -= 1; b -= 1;
	if (a > b)swap(a, b);
	long right = 0;
	for (int i = a; i < b; ++i) {
		right += nums[i];
	}
	long left = 0;
	for (int i = b; i < n; ++i) {
		left += nums[i];
	}
	for (int i = 0; i < a; ++i) {
		left += nums[i];
	}
	long ret = min(left, right);
	cout << ret << endl;
}

7.小美的好矩阵

小美定义一个矩阵是好矩阵,当且仅当该矩阵满足:

  1. 矩阵仅由’A’、‘B’、'C’三种字符组成。且三种字符都出现过。
  2. 矩阵相邻的字符都不相等。
    现在给定一个n∗m的矩阵,小美想知道有多少个3*3的子矩阵是好矩阵,你能帮帮她吗?

输入描述

第一行输入两个整数n,m,代表矩阵的行数和列数。
接下来的n行,每行输入一个仅包含大写字母的长度为m的字符串。

输出描述

输出一个整数表示答案。

示例

输入例子:
4 4
DABC
ABAB
BABA
BBAB
输出例子:
1
例子说明:
有4个3*3的子矩阵。
左上角的子矩阵出现了’D’,因此不合法。
右上角的是好矩阵。
左下角的存在两个相邻的字母相同,因此不合法。
右下角的子矩阵里没有’C’,因此不合法。

解题思路

话不多说,直接暴力。

代码

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

bool isGood(vector<vector<char>>& matrix, int n, int m) {  // 左上角起始处
	int cntA = 0, cntB = 0, cntC = 0;
	for (int i = n; i < n + 3; ++i) {
		for (int j = m; j < m + 3; ++j) {
			if (matrix[i][j] == 'A')
				cntA++;
			else if (matrix[i][j] == 'B')
				cntB++;
			else if (matrix[i][j] == 'C')
				cntC++;
			else
				return false;
			// 下右
			if (i + 1 < n + 3 && matrix[i][j] == matrix[i + 1][j] || j + 1 < m + 3 && matrix[i][j] == matrix[i][j+1])
				return false;
			// 上左
			if (i > n && matrix[i][j] == matrix[i - 1][j] || j > m && matrix[i][j] == matrix[i][j - 1])
				return false;
		}
	}
	if (cntA == 0 || cntB ==0 || cntC == 0)
		return false;
	return true;
}

int main() {
	int n, m;  // n 行 m 列
	cin >> n >> m;
	vector<vector<char>> matrix(n, vector<char>(m));
	for (int i = 0; i < n; ++i) {
		string input;
		cin >> input;
		for (int j = 0; j < m; ++j) {
			matrix[i][j] = input[j];
		}
	}
	int ret = 0;
	for (int i = 0; i < n - 2; ++i) {
		for (int j = 0; j < m - 2; ++j) {
			if (isGood(matrix, i, j))
				ret++;
		}
	}
	cout << ret << endl;
}

8.小美的蛋糕切割

小美有一个矩形的蛋糕,共分成了 n 行 m 列,共 n×m 个区域,每个区域是一个小正方形,已知蛋糕每个区域都有一个美味度。她想切一刀把蛋糕切成两部分,自己吃一部分,小团吃另一部分。小美希望两个人吃的部分的美味度之和尽可能接近,请你输出∣∣s1−s2∣|的最小值。(其中s1代表小美吃的美味度,s2 代表小团吃的美味度)。请务必保证,切下来的区域都是完整的,即不能把某个小正方形切成两个小区域。

输入描述

第一行输出两个正整数 n 和 m ,代表蛋糕区域的行数和列数。
接下来的 n 行,每行输入 m 个正整数 a_{ij} ,用来表示每个区域的美味度。

输出描述

一个整数,代表 |s_1-s_2| 的最小值。

示例

输入例子:
2 3
1 1 4
5 1 4
输出例子:
0
例子说明:
把蛋糕像这样切开:
1 1 | 4
5 1 | 4
左边蛋糕美味度之和是8
右边蛋糕美味度之和是8
所以答案是0。

解题思路

横着切,竖着切。比较横着切竖着切的最小值。注意点:只有一块,返回;看到美团的题目不要选int 都用long。

代码

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

int main() {
	int n, m;  // n 行 m 列
	cin >> n >> m;
	vector<vector<long>> cakes(n, vector<long>(m));
	long sum = 0;
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			cin >> cakes[i][j];
			sum += cakes[i][j];
		}
	}
    if(m==1 && n==1){
        cout <<  cakes[0][0] <<endl;
        return 0;
    }

	// 横着切
	long minh = 1e9;
	for (int k = 1; k < n; ++k) {// 从 1 开始,算 1 及其以下
		long down = 0;
		for (int i = k; i < n; ++i) {
			for (int j = 0; j < m; ++j) {
				down += cakes[i][j];
			}
		}
		long up = sum - down;
		minh = min(minh, abs(up - down));
	}
	// 竖着切
	long minv = 1e9;
	for (int k = 1; k < m; ++k) {// 从 1 开始,算 1 及其右边
		long right = 0;
		for (int i = 0; i < n; ++i) {
			for (int j = k; j < m; ++j) {
				right += cakes[i][j];
			}
		}
		long left = sum - right;
		minv = min(minv, abs(left - right));
	}

	cout << min(minv, minh) << endl;
}

9.小美的字符串变换

小美拿到了一个长度为n的字符串,她希望将字符串从左到右平铺成一个矩阵(先平铺第一行,然后是第二行,以此类推,矩阵有x行y列,必须保证x∗y=n,即每y个字符换行,共x行)。该矩阵的权值定义为这个矩阵的连通块数量。小美希望最终矩阵的权值尽可能小,你能帮小美求出这个最小权值吗?
注:我们定义,上下左右四个方向相邻的相同字符是连通的。

输入描述

第一行输入一个正整数n,代表字符串的长度。
第二行输入一个长度为n的、仅由小写字母组成的字符串。

输出描述

输出一个整数表示最小权值。

示例

输入例子:
9
aababbabb
输出例子:
2
例子说明:
平铺为3*3的矩阵:
aab
abb
abb
共有2个连通块,4个a和5个b。

解题思路

计算当这个矩阵是 x 行 y 列 的矩阵时,最大连通域数,最大连通域数 用一个 bool,先把能访问的都置为true 再要访问false的就cnt++。

代码

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

void backtrace(string str, vector<bool>& flags, int numrows, int numcols, int row, int col, char ch){
    int offset = row * numcols + col;
    if(row < 0 || row >=numrows || col < 0 || col >= numcols || flags[offset] || ch != str[offset]) // 越界 被访问过 不连通
        return;
    flags[offset] = true;
    backtrace(str, flags, numrows, numcols, row + 1, col, ch);
    backtrace(str, flags, numrows, numcols, row - 1, col, ch);
    backtrace(str, flags, numrows, numcols, row, col+1, ch);
    backtrace(str, flags, numrows, numcols, row, col-1, ch);
}

int main() {
    int n;
    cin >> n;
    string input;
    cin >> input;
    int ret = 1e9;
    for(int x=1; x<n; ++x){
        // x 行
        if(n%x) // 除不尽
            continue;
        // y 列
        int y = n / x;
        vector<bool> flags(n, false);
        int cnt = 0;
        for(int row = 0; row< x; ++row){
            for(int col=0; col<y; ++col){
                int offset = row*y+col;
                if(!flags[offset]){
                    ++cnt;
                    backtrace(input, flags, x, y, row, col, input[offset]);
                }
            }
        }   
        ret = min(ret, cnt);  // x 行 y 列 的最大连通域数
    }
    cout << ret <<endl;
}

总结

在没有测试用例的情况下
一、数据类型尽可能用大的,int 用 long 甚至long long float 用double。
二、错误数据的判断,要对所有输入用例是否符合规则进行判断。
三、树的题目要用拓扑,需要再学习一下,其他的AC了。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值