🍭 大家好这里是KK爱Coding ,一枚热爱算法的程序员
✨ 本系列打算持续跟新美团近期的春秋招笔试题汇总~
💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导
👏 感谢大家的订阅➕ 和 喜欢💗
文章目录
- 01.K小姐的旅行预算计划
- 题目描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 02.LYA 的旅行景点打分
- 题目描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 03.LYA 的字符串修改计划
- 题目描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 04.平衡串的数量
- 题目描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 05.K小姐的生日派对
- 问题描述
- 输入格式
- 输出格式
- 样例输入
- 样例输出
- 数据范围
- 题解
- 参考代码
- 写在最后
- 📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取~
01.K小姐的旅行预算计划
题目描述
K小姐计划去欧洲旅行,她的旅行预算总额为 k k k 欧元。旅行期间,她打算在交通、住宿和餐饮三个方面进行开销。经过仔细规划,K小姐发现,住宿的花费比交通多 x x x 欧元,而比餐饮少 y y y 欧元。请你帮助 K小姐计算出交通、住宿和餐饮三个方面各自的开销金额。
输入格式
输入包含一行,包含三个整数 k k k, x x x, y y y,分别表示旅行预算总额,住宿比交通多的金额,以及住宿比餐饮少的金额。其中, 1 ≤ k ≤ 10000 1 \le k \le 10000 1≤k≤10000, − 1000 ≤ x , y ≤ 1000 -1000 \le x, y \le 1000 −1000≤x,y≤1000。保证输入数据合法,即算出的三个开销金额均为正整数。
输出格式
输出一行,包含三个正整数,分别表示 K小姐在交通、住宿和餐饮三个方面各自的开销金额。
样例输入
5000 200 300
样例输出
1500 1700 2000
数据范围
- 1 ≤ k ≤ 10000 1 \le k \le 10000 1≤k≤10000
- − 1000 ≤ x , y ≤ 1000 -1000 \le x, y \le 1000 −1000≤x,y≤1000
题解
设交通、住宿、餐饮三个方面的开销分别为 a a a, b b b, c c c,根据题意可知:
- a + b + c = k a + b + c = k a+b+c=k
- b = a + x b = a + x b=a+x
- c = b + y c = b + y c=b+y
将后两个式子代入第一个式子,得到:
a
+
(
a
+
x
)
+
(
a
+
x
+
y
)
=
k
a + (a + x) + (a + x + y) = k
a+(a+x)+(a+x+y)=k
3
a
+
2
x
+
y
=
k
3a + 2x + y = k
3a+2x+y=k
解得:
a
=
k
−
2
x
−
y
3
a = \frac{k - 2x - y}{3}
a=3k−2x−y
然后再根据 b = a + x b = a + x b=a+x, c = b + y c = b + y c=b+y 求出 b b b 和 c c c 即可。
时间复杂度:
O
(
1
)
O(1)
O(1)
空间复杂度:
O
(
1
)
O(1)
O(1)
参考代码
- Python
k, x, y = map(int, input().split())
a = (k - 2*x - y) // 3
b = a + x
c = b + y
print(a, b, c)
- Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int k = sc.nextInt();
int x = sc.nextInt();
int y = sc.nextInt();
int a = (k - 2*x - y) / 3;
int b = a + x;
int c = b + y;
System.out.println(a + " " + b + " " + c);
}
}
- Cpp
#include <iostream>
using namespace std;
int main() {
int k, x, y;
cin >> k >> x >> y;
int a = (k - 2*x - y) / 3;
int b = a + x;
int c = b + y;
cout << a << " " << b << " " << c << endl;
return 0;
}
02.LYA 的旅行景点打分
题目描述
LYA 计划去 n n n 个旅行景点游玩,她对每个景点都有一个初始打分 a i a_i ai。在旅行过程中,如果某个景点给她留下了非常深刻的印象,她就会将该景点的打分加倍。LYA 想知道,如果她在每个景点都将打分加倍,那么最终她给所有景点的最高分是多少。请你帮她计算出每次加倍后的最高分。
输入格式
第一行输入一个正整数 n n n,代表旅行景点的数量。
第二行输入 n n n 个正整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,…,an,代表 LYA 对每个景点的初始打分。
输出格式
输出 n n n 个正整数,用空格隔开,依次代表 LYA 在每个景点将打分加倍后,当前的最高分。
样例输入
5
1 3 2 5 4
样例输出
5 6 5 10 8
数据范围
- 1 ≤ n ≤ 2 × 1 0 5 1 \le n \le 2 \times 10^5 1≤n≤2×105
- 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1≤ai≤109
题解
我们可以遍历数组,同时维护一个当前的最大值 maxv \textit{maxv} maxv。对于每个元素 a i a_i ai,将其加倍后与 maxv \textit{maxv} maxv 比较,取较大值作为新的 maxv \textit{maxv} maxv,并输出这个最大值。
时间复杂度:
O
(
n
)
O(n)
O(n),其中
n
n
n 是数组的长度。
空间复杂度:
O
(
1
)
O(1)
O(1)。
参考代码
- Python
n = int(input())
a = list(map(int, input().split()))
maxv = 0
for val in a:
maxv = max(maxv, val)
print(max(maxv, val * 2), end=' ')
- Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
int maxv = 0;
for (int val : a) {
maxv = Math.max(maxv, val);
System.out.print(Math.max(maxv, val * 2) + " ");
}
}
}
- Cpp
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int a[n];
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int maxv = 0;
for (int val : a) {
maxv = max(maxv, val);
cout << max(maxv, val * 2) << " ";
}
return 0;
}
03.LYA 的字符串修改计划
题目描述
LYA 有两个长度相等的字符串 s s s 和 t t t,她希望通过一系列操作使得这两个字符串相等。每次操作,LYA 可以选择一个字符串的一个前缀,然后选择一个字母 c c c,将选择的前缀的所有字母都替换成字母 c c c。LYA 想知道最少需要多少次操作才能使得字符串 s s s 和 t t t 相等,并希望你能给出具体的操作方案。
输入格式
第一行输入一个长度不超过 1 0 5 10^5 105 的字符串 s s s。
第二行输入一个长度与 s s s 相等的字符串 t t t。
输出格式
第一行输出一个整数 m m m,表示最少操作次数。
接下来 m m m 行,每行输出用空格隔开的三个参数 i i i, j j j, c c c,表示对第 i i i 个字符串的长度为 j j j 的前缀进行替换,将前缀所有字母替换成字母 c c c。
样例输入
aabc
abcc
样例输出
2
2 3 b
2 2 a
数据范围
- 字符串 s s s 和 t t t 的长度不超过 1 0 5 10^5 105。
题解
我们可以从字符串的末尾开始比较,找到第一个不同的位置 i i i。如果不存在不同的位置,说明两个字符串已经相等,不需要进行操作。否则,我们可以根据以下情况进行操作:
- 如果字符串 s s s 的前缀 s [ 0 , i ] s[0,i] s[0,i] 的字符都相同,那么我们只需要对字符串 t t t 的前缀 t [ 0 , i ] t[0,i] t[0,i] 进行一次替换操作,将其替换成 s [ 0 ] s[0] s[0]。
- 如果字符串 t t t 的前缀 t [ 0 , i ] t[0,i] t[0,i] 的字符都相同,那么我们只需要对字符串 s s s 的前缀 s [ 0 , i ] s[0,i] s[0,i] 进行一次替换操作,将其替换成 t [ 0 ] t[0] t[0]。
- 如果上述两种情况都不满足,那么我们需要对字符串 s s s 和 t t t 分别进行一次替换操作,将它们的所有字符都替换成同一个字母。
时间复杂度:
O
(
n
)
O(n)
O(n),其中
n
n
n 是字符串的长度。
空间复杂度:
O
(
1
)
O(1)
O(1)。
参考代码
- Python
s = input()
t = input()
n = len(s)
i = n - 1
while i >= 0 and s[i] == t[i]:
i -= 1
if i < 0:
print(0)
else:
if all(c == s[0] for c in s[:i+1]):
print(1)
print(f"2 {i+1} {s[0]}")
elif all(c == t[0] for c in t[:i+1]):
print(1)
print(f"1 {i+1} {t[0]}")
else:
print(2)
print(f"1 {n} a")
print(f"2 {n} a")
- Java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
String t = sc.nextLine();
int n = s.length();
int i = n - 1;
while (i >= 0 && s.charAt(i) == t.charAt(i)) {
i--;
}
if (i < 0) {
System.out.println(0);
} else {
boolean sEq = true, tEq = true;
for (int j = 1; j <= i; j++) {
if (s.charAt(j) != s.charAt(0)) sEq = false;
if (t.charAt(j) != t.charAt(0)) tEq = false;
}
if (sEq) {
System.out.println(1);
System.out.println("2 " + (i+1) + " " + s.charAt(0));
} else if (tEq) {
System.out.println(1);
System.out.println("1 " + (i+1) + " " + t.charAt(0));
} else {
System.out.println(2);
System.out.println("1 " + n + " a");
System.out.println("2 " + n + " a");
}
}
}
}
- Cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s, t;
cin >> s >> t;
int n = s.length();
int i = n - 1;
while (i >= 0 && s[i] == t[i]) {
i--;
}
if (i < 0) {
cout << 0 << endl;
} else {
bool sEq = true, tEq = true;
for (int j = 1; j <= i; j++) {
if (s[j] != s[0]) sEq = false;
if (t[j] != t[0]) tEq = false;
}
if (sEq) {
cout << 1 << endl;
cout << "2 " << i+1 << " " << s[0] << endl;
} else if (tEq) {
cout << 1 << endl;
cout << "1 " << i+1 << " " << t[0] << endl;
} else {
cout << 2 << endl;
cout << "1 " << n << " a" << endl;
cout << "2 " << n << " a" << endl;
}
}
return 0;
}
04.平衡串的数量
题目描述
LYA 非常喜欢研究字符串。最近她定义了一种平衡串:
- 平衡串必须仅包含两种字符,且这两种字符出现的次数相等。
例如 ababba
就是一个平衡串。
现在,LYA 有一个长度为 n n n 的字符串 s s s,她想知道 s s s 有多少个子序列是平衡串。这里的子序列是指从 s s s 中选取若干个字符(可以不连续)按照原来的顺序组成的字符串。
例如,aca
是 arcaea
的一个子序列。
输入格式
第一行包含一个正整数 n n n,表示字符串的长度。
第二行包含一个长度为 n n n 的字符串 s s s,仅由小写字母组成。
输出格式
输出一个整数,表示字符串 s s s 中平衡串子序列的个数。
答案可能很大,请将答案对 1 0 9 + 7 10^9+7 109+7 取模后输出。
样例输入
5
ababc
样例输出
9
数据范围
1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1≤n≤2×105
题解
考虑长度为 k k k 的平衡串,我们需要从字符串中选出 k k k 个位置,其中有 k 2 \frac{k}{2} 2k 个位置填入字符 a a a,另外 k 2 \frac{k}{2} 2k 个位置填入字符 b b b。
假设字符串中字符
a
a
a 的个数为
c
n
t
a
cnt_a
cnta,字符
b
b
b 的个数为
c
n
t
b
cnt_b
cntb,那么方案数就是:
C
(
c
n
t
a
,
k
2
)
×
C
(
c
n
t
b
,
k
2
)
C(cnt_a, \frac{k}{2}) \times C(cnt_b, \frac{k}{2})
C(cnta,2k)×C(cntb,2k)
其中 C ( n , m ) C(n,m) C(n,m) 表示组合数,即从 n n n 个元素中选出 m m m 个元素的方案数。
我们可以枚举字符串中所有可能出现的字符对 ( a , b ) (a,b) (a,b),统计它们出现的次数,然后计算对应的方案数,最后将所有方案数相加即可。
时间复杂度为 O ( n + 2 6 2 × n 2 ) O(n + 26^2 \times \frac{n}{2}) O(n+262×2n),即 O ( n 2 ) O(n^2) O(n2)。
参考代码
- Python
MOD = 10**9 + 7
def qmi(a, b, p):
res = 1
while b:
if b & 1:
res = res * a % p
a = a * a % p
b >>= 1
return res
def c(a, b):
if b > a: return 0
res = 1
for i in range(1, b + 1):
res = res * (a - i + 1) % MOD
res = res * qmi(i, MOD-2, MOD) % MOD
return res
n = int(input())
s = input()
cnt = [0] * 26
for ch in s:
cnt[ord(ch)-ord('a')] += 1
res = 0
for i in range(26):
for j in range(i+1, 26):
a, b = cnt[i], cnt[j]
for k in range(1, min(a,b)+1):
res += c(a, k) * c(b, k)
res %= MOD
print(res)
- Java
import java.util.*;
public class Solution {
static final int MOD = (int)1e9 + 7;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String s = sc.next();
int[] cnt = new int[26];
for (char c : s.toCharArray()) {
cnt[c - 'a']++;
}
long res = 0;
for (int i = 0; i < 26; i++) {
for (int j = i + 1; j < 26; j++) {
int a = cnt[i], b = cnt[j];
for (int k = 1; k <= Math.min(a, b); k++) {
res = (res + c(a, k) * c(b, k)) % MOD;
}
}
}
System.out.println(res);
}
static long qmi(long a, long b) {
long res = 1;
while (b > 0) {
if ((b & 1) == 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
static long c(int a, int b) {
long res = 1;
for (int i = 1; i <= b; i++) {
res = res * (a - i + 1) % MOD;
res = res * qmi(i, MOD - 2) % MOD;
}
return res;
}
}
- Cpp
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
LL qpow(LL a, LL b) {
LL res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
LL c(int a, int b) {
LL res = 1;
for (int i = 1; i <= b; i++) {
res = res * (a - i + 1) % MOD;
res = res * qpow(i, MOD-2) % MOD;
}
return res;
}
int main() {
int n;
string s;
cin >> n >> s;
int cnt[26] = {0};
for (char ch : s) cnt[ch-'a']++;
LL res = 0;
for (int i = 0; i < 26; i++) {
for (int j = i+1; j < 26; j++) {
int a = cnt[i], b = cnt[j];
for (int k = 1; k <= min(a, b); k++) {
res = (res + c(a, k) * c(b, k)) % MOD;
}
}
}
cout << res << endl;
return 0;
}
05.K小姐的生日派对
问题描述
K小姐要过生日了,她准备邀请一些朋友来参加生日派对。但是,在她的朋友圈子里,有一些人之间存在着暗恋关系。如果一个人暗恋另一个人,那么只有在他暗恋的人也被邀请的情况下,他才会愿意参加派对。
现在给定 n n n 个人和 m m m 对暗恋关系,请你帮 K小姐 计算一下,一共有多少种邀请朋友的方案可以让所有被邀请的人都愿意参加派对。由于答案可能很大,请对 1 0 9 + 7 10^9+7 109+7 取模。
输入格式
第一行包含两个正整数 n n n 和 m m m,分别表示人数和暗恋关系数。
接下来 m m m 行,每行包含两个正整数 u u u 和 v v v,表示编号为 u u u 的人暗恋编号为 v v v 的人。
输出格式
输出一个整数,表示邀请朋友的方案数对 1 0 9 + 7 10^9+7 109+7 取模后的结果。
样例输入
3 3
1 2
2 3
3 1
样例输出
1
数据范围
- 1 ≤ n , m ≤ 1 0 5 1 \leq n, m \leq 10^5 1≤n,m≤105
- 1 ≤ u , v ≤ n 1 \leq u, v \leq n 1≤u,v≤n
- 保证每个人最多只会暗恋一个人
题解
这道题可以使用并查集和树形DP来解决。
首先,我们可以将暗恋关系看作有向边,构建一个有向图。如果图中存在环,那么环上的所有人要么都被邀请,要么都不被邀请。我们可以使用并查集来找出图中的所有环,并将每个环缩成一个点。
接下来,我们将缩点后的图转化为一个森林,每个环对应森林中的一棵树。对于森林中的每棵树,我们可以使用树形DP来计算邀请方案数。对于每个节点,我们可以选择邀请或不邀请它。如果邀请它,那么它的所有子节点都必须被邀请;如果不邀请它,那么它的子节点可以任意选择邀请或不邀请。
最后,将所有树的邀请方案数相乘,再减去1(表示一个人都不邀请的方案),就得到了最终的答案。
时间复杂度:
O
(
n
+
m
)
O(n+m)
O(n+m)
空间复杂度:
O
(
n
+
m
)
O(n+m)
O(n+m)
参考代码
- Python
MOD = 10**9 + 7
def find(x):
if p[x] != x:
p[x] = find(p[x])
return p[x]
def dfs(u):
res = 1
for v in g[u]:
res = res * dfs(v) % MOD
return (res + 1) % MOD
n, m = map(int, input().split())
p = list(range(n+1))
color = [0] * (n+1)
min_node = [n+1] * (n+1)
g = [[] for _ in range(n+1)]
for i in range(m):
u, v = map(int, input().split())
pu, pv = find(u), find(v)
if pu != pv:
p[pu] = pv
else:
c = color[u]
if not c:
c = color[v]
if not c:
c = len(set(color)) + 1
min_node[c] = min(min_node[c], u, v)
while u != v:
color[u] = c
u = find(p[u])
color[v] = c
for u, v in edges:
if color[u] and not color[v]:
g[min_node[color[u]]].append(v)
elif color[v] and not color[u]:
g[min_node[color[v]]].append(u)
elif not color[u] and not color[v]:
g[v].append(u)
ans = 1
for i in range(1, n+1):
if color[i] and min_node[color[i]] == i or (not color[i] and find(i) == i):
ans = ans * dfs(i) % MOD
print((ans - 1) % MOD)
- Cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
const int MOD = 1e9 + 7;
int n, m;
vector<int> g[N];
int fa[N], color[N], minNode[N];
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int dfs(int u) {
int res = 1;
for (int v : g[u]) {
res = 1LL * res * dfs(v) % MOD;
}
return (res + 1) % MOD;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
fa[i] = i;
minNode[i] = n + 1;
}
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
int pu = find(u), pv = find(v);
if (pu != pv) {
fa[pu] = pv;
} else {
int c = color[u] ? color[u] : color[v];
if (!c) {
c = *max_element(color + 1, color + n + 1) + 1;
}
minNode[c] = min({minNode[c], u, v});
while (u != v) {
color[u] = c;
u = find(fa[u]);
}
color[v] = c;
}
}
for (int u = 1; u <= n; u++) {
for (int v : g[u]) {
if (color[u] && !color[v]) {
g[minNode[color[u]]].push_back(v);
} else if (color[v] && !color[u]) {
g[minNode[color[v]]].push_back(u);
} else if (!color[u] && !color[v]) {
g[v].push_back(u);
}
}
}
int ans = 1;
for (int i = 1; i <= n; i++) {
if ((color[i] && minNode[color[i]] == i) || (!color[i] && find(i) == i)) {
ans = 1LL * ans * dfs(i) % MOD;
}
}
cout << (ans - 1 + MOD) % MOD << endl;
return 0;
}
- Java
import java.util.*;
public class Main {
static final int N = (int)1e5 + 10;
static final int MOD = (int)1e9 + 7;
static int n, m;
static List<Integer>[] g = new List[N];
static int[] fa = new int[N];
static int[] color = new int[N];
static int[] minNode = new int[N];
static int find(int x) {
return fa[x] == x ? x : (fa[x] = find(fa[x]));
}
static int dfs(int u) {
int res = 1;
for (int v : g[u]) {
res = (int)(1L * res * dfs(v) % MOD);
}
return (res + 1) % MOD;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for (int i = 1; i <= n; i++) {
fa[i] = i;
minNode[i] = n + 1;
g[i] = new ArrayList<>();
}
for (int i = 0; i < m; i++) {
int u = sc.nextInt(), v = sc.nextInt();
int pu = find(u), pv = find(v);
if (pu != pv) {
fa[pu] = pv;
} else {
int c = color[u] != 0 ? color[u] : color[v];
if (c == 0) {
c = Arrays.stream(color, 1, n + 1).max().getAsInt() + 1;
}
minNode[c] = Math.min(minNode[c], Math.min(u, v));
while (u != v) {
color[u] = c;
u = find(fa[u]);
}
color[v] = c;
}
g[u].add(v);
g[v].add(u);
}
for (int u = 1; u <= n; u++) {
for (int v : g[u]) {
if (color[u] != 0 && color[v] == 0) {
g[minNode[color[u]]].add(v);
} else if (color[v] != 0 && color[u] == 0) {
g[minNode[color[v]]].add(u);
} else if (color[u] == 0 && color[v] == 0) {
g[v].add(u);
}
}
}
int ans = 1;
for (int i = 1; i <= n; i++) {
if ((color[i] != 0 && minNode[color[i]] == i) || (color[i] == 0 && find(i) == i)) {
ans = (int)(1L * ans * dfs(i) % MOD);
}
}
System.out.println((ans - 1 + MOD) % MOD);
}
}
写在最后
📧 KK这边最近正在收集近一年互联网各厂的笔试题汇总,如果有需要的小伙伴可以关注后私信一下 KK领取~