美团4.4笔试复盘
第一题
一天,小美在写英语作业时,发现了一个十分优美的字符串:这个字符串没有任何两个字符相同。
于是,小美随手写下了一个字符串,她想知道这个字符串的的所有子序列,有多少个是优美的。
由于答案可能会很大,输出对20210101取模后的结果。
一个字符串的子序列定义为:
原字符串删除0个或多个字符后剩下的字符保持原有顺序拼接组成的字符串为原串的子序列。
如:ab是acba的子序列,但bc则不是。在本题中。空串也为原串的子序列。
两个子序列不相同,当且仅当他们对应原串的下标不相同。如aab则含有两个子序列ab。
思路
当时做的时候就只是顺着题目上手做,找到所有子序列,然后统计其中没有相同字符的。但是静下心来好好想一下,题目说下标不相同就算子序列不相同,那么就可以把这个题目看作是组合问题,考虑每一种字符的可取方式,然后进行组合即可。比如aab,a有两个,b有一个,那么a就有三种取法(取0个a、第1个a或者第2个a),b有两种取法(0个b或第1个b),所以优美子序列就有2*3=6个。
综上,解这道题,我们只需要将每种字符的次数+1,然后相乘即可。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
long int res=1;
string a;
cin>>a;
int num[26]={0};
for(int i=0;i<a.size();i++){
num[a[i]-'a']++;
}
for(int i=0;i<26;i++){
res=res*(num[i]+1);
}
cout<<(res%20210101);
return 0;
}
第二题
今天是小美的生日,妈妈给她专门订制了一个球形的大蛋糕。
小美决定对这个蛋糕切n刀。每次切小美会选择是横着切还是竖着切。
将整个球划分经纬度。
如果是横着切的话那么小美会选择一个纬度将整个球切成上下两部分;
如果是竖着切的话那么小美会选择一个经度将整个球切成两半。
小美想知道,切n刀之后整个球被划分成了多少个部分?
思路
沿着纬度切,每切一刀增加1块
沿着经度切,每切一刀增加2块(除了第一刀)
那么总块数就是(纬度次数+1)x max(经度次数x2,1)
代码
只要统计切经度和纬度的次数,计算上面的式子就可以了
第三题
小美发明了一个函数:f(x),表示将x的所有正整数因子提取出来之后从小到大排列,
再将数字拼接之后得到的数字串。例如:10的所有因子为1,2,5,10,那么将这些因子从小到大排序之后再拼接得到的数字串为12510,即f(10)=12510。
小美十分讨厌数字k,如果f(x)中含有某个子串对应的数字等于k,那么她的不高兴度就会增加1。例如:f(8)=1248,那么其所有的子串为:1,2,4,8,12,24,48,124,248,1248,只要k等于其中任意一个值,那么小美的不高兴度就会增加1。对于每一个数,其不高兴度至多增加1。
现在,有一个长度为n的正整数序列,定义其不高兴度为序列中所有数的不高兴度的总和。
小美想要知道自己对于这个序列的总不高兴度为多少。
思路
顺着题目意思做就行。找出每个数的因数,将因数转换成字符串,对这个字符串做子串查询,计算不高兴度。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,res=0;
string k;
cin>>n>>k;
int a[n];
for(int i=0;i<n;i++){
cin>>a[i];
string s;
for(int j=1;j<=a[i];j++){//找因子,并转换为字符串
if(a[i]%j==0){
s=s+to_string(j);
}
}
for(int m=0;m<s.size();m++){
bool f=true;
for(int n=0;n<k.size();n++){//子串查询是否有 k
if(s[m]!=k[n]){
f=false;
break;
}
}
if(f==true){//若有,不高兴度加一,跳出,进行下一个数
res++;
break;
}
}
}
cout<<res;
return 0;
}
第四题
小美在路上看到一些小学生在玩跳方格,她也想跟着一起玩。
这个方格被划分为n×n的小方格,即有n行n列。
每一个小方格上面都是一个1~k的正整数。小美想依次从1,2,…,k这个顺序来跳。
一开始小美可以站在任意一个小方格。
从一个方格跳到另一个方格的花费为两个方格的曼哈顿距离。
小美想知道是否可以依照该顺序一直跳到k,如果可以,最小的总花费是多少。
两个格子(x1,y1),(x2,y2)的曼哈顿距离为:|x1-x2|+|y1-y2|。
例如(3,4),(1,6)的曼哈顿距离为|3-1|+|4-6|=4。
思路
记忆化搜索,dfs(x,y)表示从1跳到g[x][y]
的最少花费,那么dfs(x,y)=min(dfs(i,j)+abs(x-i)+abs(y-j))
,其中(i,j)满足(g[i][j]+1=g[x][y]
)
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
int g[N][N];
int dp[N][N];
int n, k;
void dfs(int x, int y){
if(dp[x][y] != -1) return;
if(g[x][y] == 1) {
dp[x][y] = 0;
return;
}
int ret = 1e9;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ ){
if(g[i][j] == g[x][y]-1){
dfs(i, j);
ret = min(ret, dp[i][j] + abs(x-i)+abs(y-j));
}
}
dp[x][y] = ret;
}
int main()
{
cin >> n >> k;
set<int> st;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ ){
cin >> g[i][j];
if(g[i][j] >= 1 && g[i][j] <= k)
st.insert(g[i][j]);
}
if(st.size() != k){
cout << -1 << endl;
return 0;
}
int res = 1e9;
for(int i = 1; i <= n; i ++ )
for(int j = 1; j <= n; j ++ ){
if(g[i][j] == k) {
memset(dp, -1, sizeof(dp));
dfs(i, j);
res = min(res, dp[i][j]);
}
}
cout << res << endl;
return 0;
}
第五题
有一个长度为A的数组和长度为B的数组
数组的每个数都代表了一颗糖果的甜度(可能为0或负值)
拿糖果的时候必须从第一个开始拿,可以拿任意多个,问最多甜度多少
思路
维护两个前缀和,最大值相加即可
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int m,n;
cin>>m>>n;
int a[m],b[n];
int temp,maxa=0,maxb=0;
temp=0;
for(int i=0;i<m;i++){
cin>>a[i];
temp=temp+a[i];
maxa=max(maxa,temp);
}
temp=0;
for(int i=0;i<n;i++){
cin>>b[i];
temp=temp+b[i];
maxb=max(maxb,temp);
}
cout<<(maxa+maxb);
return 0;
}