24年春招/暑期实习-阿里-笔试真题卷(2)

第一题:支付宝活动

在线测评链接:http://121.196.235.151/p/P1137

题目描述

众所周知,在一些消费支付的场合中,往往有“支付宝九五折”的优惠。这天薯条哥来到了超市购买物品,一共有 n n n种物品,每种物品只能购买一个,但有的物品支持优惠活动,有的并不支持。恰好本超市的结账是有“支付宝九五折”优惠的,薯条哥的支付宝余额还剩 k k k元,他想知道他仅使用支付宝进行支付的话最多能买几件物品?

输入描述

输入包含三行。

第一行两个正整数 n , k ( ≤ n ≤ 1 0 5 ) , ( 1 ≤ k ≤ 1 0 9 ) n,k(\le n\le 10^5),(1\le k\le 10^9) n,k(n105),(1k109)
第二行包含 n n n个正整数 a i ( 1 ≤ a i ≤ 1 0 4 ) a_i(1\le a_i\le 10^4) ai(1ai104)表示每个物品的价格。

第三行一个长度为 n n n的只含有0和1的字符串,表示每个物品是否支持优惠。(如果是1代表第 i i i个物品支持优惠,否则不支持。)

输出描述

输出一行一个整数表示答案

样例

输入

3 975
1000 500 500
0 0 1

输出

2

思路:贪心+排序

首先,我们可以计算打折商品打折后的价格,计算好之后,将所有商品按照价格从小到大排序,然后枚举即可,直到枚举到钱不够的情况,停止枚举,输出答案。

注意:本题需要使用double存储,否则会丢失精度导致计算结果不正确

C++

#include <bits/stdc++.h>
using namespace std;
using namespace std;
const int N=1e5+10;
int n;
double a[N],k;
string s;
int main() {
    cin>>n>>k;
    for(int i=0;i<n;i++)cin>>a[i];
    cin>>s;
    for(int i=0;i<n;i++){
        if(s[i]=='1'){
            a[i]*=0.95;  //计算打折后的价格
        }
    }
    sort(a,a+n);
    int ans=0;
    double sum=0;
    for(int i=0;i<n;++i){
            sum+=a[i];
            if(sum<=k) ans++;
            else break;
    }
    cout<<ans<<endl;
    return 0;
}

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        double k = scanner.nextDouble();
        double[] a = new double[n];
        for (int i = 0; i < n; i++) {
            a[i] = scanner.nextDouble();
        }
        String s = scanner.next();
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '1') {
                a[i] *= 0.95;  // 计算打折后的价格
            }
        }
        Arrays.sort(a);
        int ans = 0;
        double sum = 0;
        for (int i = 0; i < n; ++i) {
            sum += a[i];
            if (sum <= k) ans++;
            else break;
        }
        System.out.println(ans);
    }
}

Python

n, k = map(int, input().split())
a = list(map(float, input().split()))
s = input()

for i in range(n):
    if s[i] == '1':
        a[i] *= 0.95

a.sort()
ans = 0
sum = 0
for price in a:
    sum += price
    if sum <= k:
        ans += 1
    else:
        break

print(ans)

第二题:元辅音方案数

在线测评链接:http://121.196.235.151/p/P1138

题目描述

ak机定义一个字符串的权值是:字符串辅音数量和元音数量的差的绝对值。
例如,“arcaea"的权值是 2,因为有4个元音,2 个辅音权值为 ∣ 4 − 2 ∣ |4-2| ∣42∣=2.现在ak机拿到了一个字符串,她想把这个字符串切成两个非空字符串,需要满足两个字符串的权值相等。ak机想知道,有多少种不同的切割方式?我们定义,元音有"aeiou"这五种,其余字母均为辅音,

输入描述

一个仅包含小写字母的字符串,长度不超过 2 × 1 0 5 2\times 10^5 2×105

输出描述

切割方案数。

样例

输入

arcaea

输出

2

思路:前缀和

我们可以使用前缀和数组 p r e 1 , p r e 2 pre1,pre2 pre1,pre2分别统计前 i i i个字符中的元音数量和辅音数量

当我们枚举到位置 i i i时,我们可以根据前缀和数组计算出左边子串的元音数量和辅音数量 c 1 , c 2 c1,c2 c1,c2

其中 c 1 = p r e 1 [ i ] − p r e 1 [ 0 ] , c 2 = p r e 2 [ i ] − p r e 2 [ 0 ] c1=pre1[i]-pre1[0],c2=pre2[i]-pre2[0] c1=pre1[i]pre1[0],c2=pre2[i]pre2[0]

然后再拿总的元音数量和辅音数量计算出右半边对应的数量 c 3 , c 4 c3,c4 c3,c4

如果有 ∣ c 1 − c 2 ∣ = ∣ c 3 − c 4 ∣ |c1-c2|=|c3-c4| c1c2∣=c3c4∣,则答案+1。

本题我们可以一边枚举一边计算,可以用 c 1 , c 2 c1,c2 c1,c2这两个变量来代替前缀和数组,有点类似前后缀分解的思想。

C++

#include<bits/stdc++.h>
using namespace std;
const int N=2E5+10;
string s;
int w[N],S[N];
int main(){
    cin>>s;
    int n=s.size();
    set<char>st={'a','e','i','o','u'};
    int cnt1=0,cnt2=0;
    for(int i=0;i<n;i++){
        if(st.count(s[i])){
            cnt1++;
        }
        else{
            cnt2++;
        }
    }
    int c1=0,c2=0,res=0;
    for(int i=0;i<n;i++){
        if(st.count(s[i])){
            c1++;
        }
        else{
            c2++;
        }
        int c3=cnt1-c1,c4=cnt2-c2;
        if(abs(c1-c2)==abs(c3-c4)){
            res++;
        }
    }
    cout<<res<<endl;
    return 0;
}

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.next();
        int n = s.length();
        Set<Character> st = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u'));
        int cnt1 = 0, cnt2 = 0;
        
        for (int i = 0; i < n; i++) {
            if (st.contains(s.charAt(i))) {
                cnt1++;
            } else {
                cnt2++;
            }
        }
        
        int c1 = 0, c2 = 0, res = 0;
        for (int i = 0; i < n; i++) {
            if (st.contains(s.charAt(i))) {
                c1++;
            } else {
                c2++;
            }
            int c3 = cnt1 - c1, c4 = cnt2 - c2;
            if (Math.abs(c1 - c2) == Math.abs(c3 - c4)) {
                res++;
            }
        }
        
        System.out.println(res);
    }
}

Python

s = input()
n = len(s)
st = {'a', 'e', 'i', 'o', 'u'}
cnt1, cnt2 = 0, 0

for char in s:
    if char in st:
        cnt1 += 1
    else:
        cnt2 += 1

c1, c2, res = 0, 0, 0
for char in s:
    if char in st:
        c1 += 1
    else:
        c2 += 1
    c3, c4 = cnt1 - c1, cnt2 - c2
    if abs(c1 - c2) == abs(c3 - c4):
        res += 1

print(res)

第三题:变化数组

在线测评链接:http://121.196.235.151/p/P1139

题目描述

薯条哥有一个长度为 n n n 的数组 a a a。他想要使得所有 a i a_i ai 的最大公因子是一个素数。即 g c d ( a 1 , a 2 . . . , a n ) gcd(a_1,a_2...,a_n) gcd(a1,a2...,an)是一个素数。他可以对数组进行任意次操作。

具体的:每次操作,他会选择 i , j i,j i,j两个下标,同时执行: a i = a i + 2 , a j = a j − 2 a_i= a_i+2,a_j=a_j-2 ai=ai+2,aj=aj2
请问他是否有可能在任意次操作内将数组变成符合要求的。如果可以,请输出所有可能的最大公因数。

注意,这里要保证 a j a_j aj在操作后仍然是正数,即不能选择 a j ≤ 2 a_j\le 2 aj2

输入描述

输入包含两行。

第一行一个正整数 n ( 2 ≤ n ≤ 2 × 1 0 5 ) n(2 ≤n≤2\times 10^5) n(2n2×105)表示数组长度。

第二行 n n n个正整数 a i ( 1 ≤ a i ≤ 1 0 6 ) a_i(1\le a_i\le 10^6) ai(1ai106)表示这个数组

输出描述

输入包含一行或两行。

如果可以输出“YES”否则输出“NO”(不含双引号)

如果答案为“YES”,则第二行按照升序输出所有可行的数组 gcd.

样例1

输入

4
1 3 5 9

输出

YES
3

说明

可以选择一次 i = 1 , j = 3 i= 1,j=3 i=1,j=3,这样一来数组变成:

[ 3 , 3 , 3 , 9 ] [3,3,3,9] [3,3,3,9] g c d = 3 。 gcd =3。 gcd=3

可以证明只有 3这一个答案

样例2

输入

4
2 2 2 2

输出

YES
2

思路:数论+分类讨论

首先观察可知,操作有两个特点

  • 不会改变元素的奇偶性,奇数操作完了还是奇数,偶数亦然
  • 不会改变数组的元素总和,总和 s u m sum sum是一个固定值

那么我们首先考虑一种极端情况数组所有元素都是偶数,那么一定有且仅有一个公素数:2,不会存在其他素数了,因此直接输出2即可

本题有一个重要结论,任何奇数/偶数,都可以通过+2、-2来变成任意一个奇数/偶数。

对于数组中又有奇数,又有偶数的情况,我们可以枚举总和 s u m sum sum的素因子(素因子一定是奇数,唯一的偶数素因子就是2,2不可能满足条件)

我们可以枚举所有素因子 x x x,对于枚举到的素因子 x x x,对于数组中的所有奇数,其值至少要等于 x x x,或者就等于 2 x , 3 x , . . . 2x,3x,... 2x,3x,...

对于数组中的所有偶数,其值至少要等于 2 x 2x 2x,或者就等于 4 x , 6 x , . . . 4x,6x,... 4x,6x,...

因此一定要满足下面三个条件

条件1 x x x s u m sum sum的因子

条件2 x × ( n + c n t ) ≤ s u m x\times (n+cnt)\le sum x×(n+cnt)sum,其中 c n t cnt cnt为数组中偶数的数量(因为偶数至少要为 2 x 2x 2x)

条件3 x > 2 x>2 x>2,因为数组里面有奇数,因此 x x x一定是奇素数

按照上述方式统计素因子即可

C++

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N],n;
long long sum;
int main() {
    cin>>n;
    int cnt=0;  //记录数组中偶数的个数
    for(int i=0;i<n;i++){
        cin>>a[i];
        sum+=a[i];
        if(a[i]%2==0){
            cnt++;
        }
    }
    if(cnt==n){  //如果数组中所有的数字都是偶数,有且仅有一个公共素因子:2
        puts("YES");
        puts("2");
        return 0;
    }
    vector<int>res;  //记录所有合法的素因子
    long long total=sum;
    for(long long i=2;i*(n+cnt)<=total;i++){
        if(sum%i==0&&i!=2){
            res.push_back(i);
        }
        while(sum%i==0){  //去除sum中所有i的因子,类似质因数分解的思想
            sum/=i;
        }
        
    }
    if(!res.size())puts("NO");
    else{
        puts("YES");
        for(int &x:res){
            cout<<x<<" ";
        }
    }
    return 0;
}

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] a = new int[n];
        long sum = 0;
        int cnt = 0;  // 记录数组中偶数的个数
        for(int i = 0; i < n; i++){
            a[i] = scanner.nextInt();
            sum += a[i];
            if(a[i] % 2 == 0){
                cnt++;
            }
        }
        if(cnt == n){  // 如果数组中所有的数字都是偶数,有且仅有一个公共素因子:2
            System.out.println("YES");
            System.out.println("2");
            return;
        }
        List<Integer> res = new ArrayList<>();  // 记录所有合法的素因子
        long total = sum;
        for(long i = 2; i * (n + cnt) <= total; i++){
            if(sum % i == 0 && i != 2){
                res.add((int)i);
            }
            while(sum % i == 0){  // 去除sum中所有i的因子,类似质因数分解的思想
                sum /= i;
            }
        }
        if(res.isEmpty()){
            System.out.println("NO");
        } else {
            System.out.println("YES");
            for(int x : res){
                System.out.print(x + " ");
            }
        }
    }
}

Python

n = int(input())
a = list(map(int, input().split()))
sum = 0
cnt = 0  # 记录数组中偶数的个数
for i in range(n):
    sum += a[i]
    if a[i] % 2 == 0:
        cnt += 1
if cnt == n:  # 如果数组中所有的数字都是偶数,有且仅有一个公共素因子:2
    print("YES")
    print("2")
else:
    res = []  # 记录所有合法的素因子
    total = sum
    i = 2
    while i * (n + cnt) <= total:
        if sum % i == 0 and i != 2:
            res.append(i)
        while sum % i == 0:  # 去除sum中所有i的因子,类似质因数分解的思想
            sum /= i
        i += 1
    if not res:
        print("NO")
    else:
        print("YES")
        print(" ".join(map(str, res)))
  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值