2024年美团春招第一场笔试(技术)

时间:2025-02-14 07:43:25

1.

小美的平衡矩阵

小美拿到了一个n∗n的矩阵,其中每个元素是 0 或者 1。
小美认为一个矩形区域是完美的,当且仅当该区域内 0 的数量恰好等于 1 的数量。
现在,小美希望你回答有多少个i∗i的完美矩形区域。你需要回答1≤i≤n的所有答案。

解法:很明显,i若为奇数,则不可能是完美的。

对于偶数,枚举每个面积为 i*i的矩阵,判断一下这个矩阵的前缀和是不是面积的一半,是的话则符合题意,这题考察一个二维前缀和。

#include<iostream>

using namespace std;
const int N = 210;

int g[N][N], s[N][N];
int n;
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        string str;
        cin >> str;
        int k = 0;
        for (int j = 1; j <= n; j++) {
            g[i][j] = str[k++] - '0';
            s[i][j] = g[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
        }
    }

    for (int i = 1; i <= n; i++) {
        if (i % 2) {
            cout << "0" << '\n';
            continue;
        }
        int res = 0;
        for (int j = i; j <= n; j++) {
            for (int k = i; k <= n; k++) {
                int sum = s[j][k] - s[j][k - i] - s[j - i][k] + s[j - i][k - i];
                if (sum == (i * i) / 2)res++;
            }
        }
        cout << res << '\n';
    }
}

2.

2.

小美的数组询问

小美拿到了一个由正整数组成的数组,但其中有一些元素是未知的(用 0 来表示)。
现在小美想知道,如果那些未知的元素在区间[l,r]范围内随机取值的话,数组所有元素之和的最小值和最大值分别是多少?
共有q次询问。

解法:先把非0的数累加起来,然后接着想,怎样能让和最小和最大,很明显嘛,区间【L,R】是升序的,那么让那些未知数全部取L,自然加起来就是最小的,全部取R,自然就是最大的,纯纯送分题没啥好说的。

#include<iostream>
#define int long long
using namespace std;

int n,q;
signed main()
{
	cin>>n>>q;
	int sum = 0;
	int res = 0;
	
	for(int i = 1;i <= n; i++)
	{
		int x;
		cin>>x;
		if(x==0)res++;
		else sum +=x;
	}
	
	while(q--)
	{
		int l,r;
		cin>>l>>r;
		cout<<sum + res*l<<" "<<sum+res*r<<'\n';
	}
	return 0;
} 

3.

小美的 MT

MT 是美团的缩写,因此小美很喜欢这两个字母。
现在小美拿到了一个仅由大写字母组成字符串,她可以最多操作k次,每次可以修改任意一个字符。小美想知道,操作结束后最多共有多少个'M'和'T'字符?

解法:纯模拟题。遇到非M非T字符,只要还有操作次数,就直接变成M或者T就可以了,最后统计一下有多少个就可以了。

#include<iostream>

using namespace std; 

int main()
{
	int n,k;
	
	scanf("%d%d",&n,&k);
	
	int res = 0,ans=0;
	
	string str;
	
	cin>>str;
	for(int i = 0;i<();i++)
	{
		if(str[i]=='T')res++;
		else if(str[i]=='M')res++;
		else ans++;
	}
	
	cout<<res + min(ans,k)<<'\n';
	return 0;
}

4.小美的朋友关系

小美认为,在人际交往中,但是随着时间的流逝,朋友的关系也是会慢慢变淡的,最终朋友关系就淡忘了。
现在初始有一些朋友关系,存在一些事件会导致两个人淡忘了他们的朋友关系。小美想知道某一时刻中,某两人是否可以通过朋友介绍互相认识?
事件共有 2 种:
1 u v:代表编号 u 的人和编号 v 的人淡忘了他们的朋友关系。
2 u v:代表小美查询编号 u 的人和编号 v 的人是否能通过朋友介绍互相认识。

注:介绍可以有多层,比如 2 号把 1 号介绍给 3 号,然后 3 号再把 1 号介绍给 4 号,这样 1 号和 4 号就认识了。

解法:判断两个人是不是认识或者间接认识,很明显就是让我们判断在不在一个集合里面,顺着这个想法很快就想到并查集了,但是这个题目要删边(淡忘朋友关系),所以直接正向并查集不好做,并查集只能加边,所以这里要用反向并查集,逆序处理那些事件。

先把事件存起来,然后把是朋友关系的且没有被淡忘的关系并查集加边,然后从最后一个事件逆序往上做,这里要注意的一点::::要考虑重边!!!!!,比如添加{a,b}和{b,a},这应该是同一条边,要特别判断一下,然后反向处理的时候把答案也存起来,再把答案逆序打印出来就好了。

#include<iostream>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<set>
using namespace std;
typedef pair<int,int>PII; 
// 反向并查集 
set<pair<int,int>>hashs,all;
unordered_map<int,int>p;
unordered_set<int>person;
int n,m,q;
const int N=1000100;
//int p[N];
struct OP{
	int op, a,b;
}Op[N];
int find(int x)
{
	if(p[x]!=x)p[x]=find(p[x]);
	return p[x];
}
int main()
{
//	for(int i = 1;i<=n;i++)p[i]=i;
	cin>>n>>m>>q;
	for(int i = 1; i<=m;i++)
	{
		int a,b;
		cin>>a>>b;
		({a,b});
		({a,b});
		(a);
		(b);
	}	
//	for(auto t : hashs)
//	{
//		cout<<<<" "<<<<endl;
//	}
	for(int i = 0; i < q;i++)
	{
		int op,a,b;
		cin>>op>>a>>b;
		Op[i]={op,a,b};
		(a);
		(b);
		if(op==1)
		{
			({a,b});
			({b,a});
		}
	}
	for(auto t : person)
	{
		p[t]=t;
	}
	for(auto pii:hashs)
	{
		int a= ;
		int b= ;
		p[find(a)]=find(b);
	}
	vector<string>ans;
	for(int i = q-1;i>=0;i--)
	{
		int op =Op[i].op;
		int a=Op[i].a;
		int b= Op[i].b;
		if(op==1){
			if(({a,b})||({b,a}))
			p[find(a)]=find(b);
		}
		else
		{
			if(find(a)==find(b))
			{
				ans.push_back("Yes");
				
			}
			else ans.push_back("No");
		}
	}
	
	for(int i = ()-1;i>=0;i--)
		cout<<ans[i]<<'\n';
	return 0;
} 

5.

小美的区间删除

小美拿到了一个大小为n的数组,她希望删除一个区间后,使得剩余所有元素的乘积末尾至少有k个 0。小美想知道,一共有多少种不同的删除方案?

解法:乘积末尾至少要有k个0,那么剩余区间里的数2的因子和5的因子均不能少于k个,

可以先把每个数2的因子和5的因子统计出来,并且累加到c2和c5上
接着采用双指针做法,L指针固定左端点,R指针固定右端点,[L,R]这段区间表示要删除的区间

R指针每右移一位,若当前剩余的因子数仍满足k个,那么就会增加R - L +1个可行删除区间(会影响前R-L个数,并且多了当前新增的这个数,所以是R-L+1),若不满足了,说明左指针需要移动了。

#include<iostream>
#include<unordered_map>
#include<cmath>
using namespace std;
typedef long long LL;
const int N = 1000010;
int n,k;
int s[N];
LL sum;

LL c2,c5;
LL cnt2[N],cnt5[N];

int getNums(int x,int num)
{
	int res=0;
	
	while(x%num==0)
	{
		x/=num;
		res++;
	}
	
	return res;
}
int main()
{
	cin>>n>>k;
	
	for(int i = 1;i<=n;i++)
	{
		int x;
		cin>>x;
		cnt2[i] = getNums(x,2);
		cnt5[i] = getNums(x,5);
		c2+=cnt2[i];
		c5+=cnt5[i];
	//	cout<<cnt2[i]<<" "<<cnt5[i]<<'\n';
	}
//	cout<<c2<<" "<<c5<<'\n';
	LL res=0;
	for(int l = 1, r= 1; r<=n;r++)
	{
		c2-=cnt2[r];
		c5-=cnt5[r];
		while(min(c2,c5)<k&&l<=n)
		{
			c2+=cnt2[l];
			c5+=cnt5[l];
			l++;
		}
		if(r>=l)
		res +=r-l+1;
	}
	printf("%lld",res);
}