2024-3-16美团笔试题(A~E)

提前一小时AK纪念

A:

概述:有n个商品,价值ai元,有一个x元的满减,一个y元的优惠卷,保证一定可以用到满减和优惠卷,问购买这n个商品需要多少元

思路:求和,减去x,y即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>

#define _for(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;
int main(void)
{
    int n;
    scanf("%d",&n);
    
    long long sum=-0;
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        sum+=x;
    }
    int a,b;
    scanf("%d%d",&a,&b);
    printf("%lld",sum-a-b);
}

B:

概述:给定一个只含有大小写字母的字符串,问至少可以变化几个字母的大小写,使得其满足以下条件之一

1.只含有大写字母

2.只含有小写字母

3.除首字母含有大写字母外,其余字母均为小写

思路:计算三种方案所需的开销,取min即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>

#define _for(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;
char s[100500];
int main(void)
{
    scanf("%s",s+1);
    int len=strlen(s+1);
    int cnt1=0,cnt2=0;
    _for(i,1,len)
    {
        if(s[i]<='z'&&s[i]>='a') cnt1++;
        else cnt2++;
    }
    printf("%d",min(cnt2-(s[1]<='Z'&&s[1]>='A'),cnt1));
}

C:

概述:有一个长度为n的数组,每个数组有一个权值vali,有q次操作,每次操作给定一个数字x,之后除数组中第x个数以外,所有数的权值均翻倍,问q次操作后,所有数字之和mod 1e9+7是多少

思路:与其让所有数字翻倍,不如让该数组除以2,然后在操作结束后,让所有数字翻倍q次即可

当然,对于没有接触过数论和离散数学的同学,并不知道在同余系下的除法如何处理,因此只需要记录每个数字被除二了多少次,然后轮到他的时候给他翻倍q-ti 次即可(ti 为第i个数被除二的次数),对于翻倍q次的操作,我们采用快速幂去计算答案即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>

#define _for(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define MAXN 100050
const int mod=1000000007;
using namespace std;
int arr[MAXN];
int cnt[MAXN];
inline int quickpow(int x,int k)
{
    int res=1;
    while(k)
    {
        if(k&1) res=1ll*res*x%mod;
        x=1ll*x*x%mod;
        k>>=1;
    }
    return res;
}
int main(void)
{
    int n,q;
    scanf("%d%d",&n,&q);
    _for(i,1,n)
    {
        scanf("%d",&arr[i]);
    }
    _for(i,1,q)
    {
        int x;
        scanf("%d",&x);
        cnt[x]--;
    }
    int sum=0;
    _for(i,1,n)
    {
        sum+=1ll*quickpow(2,q+cnt[i])*arr[i]%mod;
        sum%=mod;
    }
    printf("%d",sum);
}

D:

概述:有一个数组,该数组仅仅含有1和2,区间[l,r]的权值为数组中第l个数到第r个数中的众数(如果有多个,则取较小的那个),问该数组中,每个区间的权值和为多少

前置知识:树状数组/线段树

思路:考虑有哪些区间的众数为2

设f(x)为数组在区间[0,x]中有多少个数字为2,若区间[l,r]的众数为2,那么该区间的2一定比1多

2的数量:f(r)-f(l-1),1的数量:r-l+1-f(r)+f(l-1)

因此,该区间只需2*f(r)-r>2*f(l)-(l-1)即可

设g(x)=2*f(x)-x,因此,对于每个r结尾的区间,我们只需要知道有多少个l满足g(l)<g(r)即可,因此,我们考虑枚举右端点r,然后通过线段树或者树状数组维护一个可以动态添加以及计算区间和/前缀和的桶即可,然后在计算过所有[l,r]区间的值后,将g(r)添加进桶中即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>

#define _for(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;
#define MAXN 200050

int n;
int tree[MAXN<<4];
int arr[MAXN];
int sum[MAXN];
int val[MAXN];

inline int lowbit(int x)
{
    return x&(-x);
}
inline void update(int x,int k)
{
    for(int i=x;i<=2*n+10;i+=lowbit(i))
    {
        tree[i]+=k;
    }
}
inline int query(int x)
{
    int sum=0;
    for(int i=x;i;i-=lowbit(i))
    {
        sum+=tree[i];
    }
    return sum;
}
int main(void)
{
    scanf("%d",&n);
    _for(i,1,n)
    {
        scanf("%d",&arr[i]);
        sum[i]=sum[i-1]+(arr[i]==2);
    }
    update(1+n,1);
    long long cnt=0;
    _for(i,1,n)
    {
        val[i]=2*sum[i]+n-i+1;
        cnt+=query(val[i]-1);
        update(val[i],1);
    }
    printf("%lld",1ll*n*(n+1)/2+cnt);
}

E:

概述:对于一个排列,问,对于该排列中的每一个数字,将其变为其相反数后,该排列的逆序对有多少个

前置知识:树状数组维护逆序对

思路:由于取反后为负数,该数字一定小于原本的任何一个数字,我们可以先计算原排列的逆序对数目,然后对于每一个数字,计算他被取反后,能使该排列的逆序对变化多少

对于第i个数字,他在变为最小的数字后,在他之前的所有比他小的数字都会和他组成逆序对,在他之后所有比他小的数字会由原本构成逆序对转变成不构成逆序对,设在他之前比他小的数字的数量为x,因此该次操作的带来的变化为x-(vi-1-x),考虑原本的逆序对数目k,则第i个数字取反后的逆序对数目为k+x-(vi-1-x)

参考上题用树状数组维护即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>

#define _for(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)

using namespace std;
#define MAXN 200050
int n;
int arr[MAXN];
int tree[MAXN];
inline int lowbit(int x)
{
    return x&(-x);
}
inline void update(int x,int k)
{
    for(int i=x;i<=n;i+=lowbit(i))
    {
        tree[i]+=k;
    }
}
inline int query(int x)
{
    int sum=0;
    for(int i=x;i;i-=lowbit(i))
    {
        sum+=tree[i];
    }
    return sum;
}
int main(void)
{
    scanf("%d",&n);
    long long sum=0;
    _for(i,1,n)
    {
        int x;
        scanf("%d",&x);
        sum+=query(n)-query(x);
        int temp=query(x-1);
        arr[i]=temp-(x-1-temp);
        update(x,1);
    }
    _for(i,1,n)
    {
        printf("%lld ",sum+arr[i]);
    }
}

;Bval

}

全部评论
看到大伙都16.6我就放心了
18 回复 分享
发布于 03-16 21:09 新加坡
不会 树状数组
7 回复 分享
发布于 03-16 21:06 香港
卧槽,10分钟一道题?
4 回复 分享
发布于 03-17 00:52 广东
佬,最后一题“temp-(x-1-temp);”这是啥意思。
3 回复 分享
发布于 03-16 21:09 湖南
xd是不是acm✌?
3 回复 分享
发布于 03-16 21:19 浙江
大佬tql
2 回复 分享
发布于 03-16 21:03 湖北
厉害,大佬,但是为什么我第三题和你一样的思路,但是只能过16.67%,还一直说我超时
2 回复 分享
发布于 03-16 21:04 北京
第三道题不超时嘛?测试用例可以全部过?
2 回复 分享
发布于 03-16 21:08 广东
tql,一小时ak
2 回复 分享
发布于 03-16 21:10 山东
同一小时ak,难度中规中矩
2 回复 分享
发布于 03-16 21:11 江苏
佬,得物也要笔试了,可以看看主页帖子
2 回复 分享
发布于 03-16 21:41 陕西
佬,看看主页帖子科瑞国际计算机专项春招
2 回复 分享
发布于 03-16 21:48 陕西
佬是大二吗?太巨了
2 回复 分享
发布于 03-16 23:34 湖南
tql
1 回复 分享
发布于 03-16 21:03 辽宁
大佬跪了
1 回复 分享
发布于 03-16 21:04 浙江
真是大佬
1 回复 分享
发布于 03-16 21:04 四川
第三题同样思路,用 python 只能过 16.7%
1 回复 分享
发布于 03-16 21:05 新加坡
tql佬
1 回复 分享
发布于 03-16 21:07 广东
佬,我 C 题也是这样的思路,不过翻倍 q-ti 次方的时候用的左移,通过总是 16.7。 后来担心左移的时候爆了,就改成每移 8 次做一个模法,最后超时且通过率还是 16.7 佬知道为什么吗
1 回复 分享
发布于 03-16 21:08 湖北
佬是真的强
1 回复 分享
发布于 03-16 21:09 广东

相关推荐

蚂蚁 基架java (n+6)*16 签字费若干
点赞 评论 收藏
分享
71 182 评论
分享
牛客网
牛客企业服务