阿里暑期实习笔试准备

在牛客上做了2021的4星和2星编程题。

晚上应该是寄了,然后总结一下。

3月4号的题,写个大概,应该是要保密的。

1.序列排列组合,需要排个序。a[i]!=i。

2.没看懂。

3.做n个题,然后需要多少天做完,要求一天多一天少。

阿里算法岗3月4号笔试情况(附带题解)_笔经面经_牛客网 (nowcoder.com)https://www.nowcoder.com/discuss/854352?type=post&order=recall&pos=&page=1&ncTraceId=&channel=-1&source_id=search_post_nctrack&gio_id=AD919A4C33297B0DDBB8D15812FA3CF9-1646540234975感觉没有下面这20个题难。

 从牛客上找的。

  

1完美对

输入描述:

第一行两个数字n,k。
接下来n行,第i行k个数字表示。

输出描述:

一行一个数字表示答案

输入例子1:

5 3
2 11 21
19 10 1
20 11 1
6 15 24
18 27 36

输出例子1:

3
#include<bits/stdc++.h>
using namespace std;

int main(){
    int n,k;
    cin >> n >> k;
    vector<vector<int>> q(n,vector<int>(k));
    /*两个序列是不是完美对,关键在于它们的差分序列是否互为相反数。
    已知序列a,统计它的完美对个数,只需要查询其余序列即可。*/
    for(int i=0;i<n;i++) 
        for(int j=0;j<k;j++)
            cin>>q[i][j];
    int cnt = 0;
    unordered_map<string, int> hash;//为了方便查询。将序列b的差分序列转成string,以1个key查询。
    for(int i=0;i<n;i++){
        string diffa = "";//序列a 的差分
        string diffA = "";//序列a的完美对 的差分。
        for(int j=0;j<k-1;j++){
            int tmpDa = q[i][j] - q[i][j+1];
            int tmpDA = q[i][j+1] - q[i][j];
            diffa += tmpDa>=0 ? "+" + to_string(tmpDa) : to_string(tmpDa);//主要是为了分割数字,.正数加+号,负数
            //自带-号
            diffA += tmpDA>=0 ? "+" + to_string(tmpDA) : to_string(tmpDA);
        }
        if(hash.find(diffA) != hash.end()) //如果找到了
            cnt += hash[diffA];//diffa的完美对
        hash[diffa]++;//序列a也是某个序列的完美对,+1
    }
    cout <<cnt <<endl;
    return 0;
}
//牛客347830471号

sync_with_stdio 是输入同步开关:(7条消息) sync_with_stdio_底层码农-CSDN博客_sync_with_stdio

2选择物品

输入例子1:

4 1

输出例子1:

1
2
3
4

输入例子2:

5 2

输出例子2:

1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
#include<iostream>
#include<vector>
using namespace std;
void dfs(vector<int>&temp, int n, int m, int index){
    if (temp.size() == m){
        //输出temp
        for (int i = 0; i < temp.size(); i++){
            if (i == 0) cout << temp[i];
            else cout << " " << temp[i];
        }
        cout << endl;
        return;
    }
    else{
        for (int i = index; i <= n; i++){
            temp.push_back(i);
            dfs(temp, n, m, i + 1);
            temp.pop_back();
        }
    }
}
int main(){
    int n, m;
    while (cin >> n >> m){
        vector<int> temp;
        dfs(temp,n,m,1);
    }
    return 0;
}

//来自 <https://www.nowcoder.com/test/question/done?tid=52828485&qid=1664933#summary> 

3小强去春游

输入例子1:

2
4
2 10 12 11
4
2 3 7 8

输出例子1:

37
19
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,t,a[100005];
int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int i,j;
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(i=1; i<=n; i++)
            cin>>a[i];
        sort(a+1,a+n+1);
        ll ans=0;
        while(n>=4)
        {
            ans+=min(a[1]*2+a[n-1]+a[n],a[1]+2*a[2]+a[n]);
            n-=2;
        }
        if(n==3)
            ans+=a[1]+a[2]+a[3];
        else if(n==2)
            ans+=a[2];
        else if(n==1)
            ans+=a[1];
        cout<<ans<<endl;
    }
    return 0;
}

大佬 零葬 分享了解题思路。零葬的个人主页_牛客网 (nowcoder.com)

剩余人数不少于4的时候,比较如下两种操作方案看哪一种用时更少:

1.最轻的人由重到轻每次带过去一个人然后开船回来(为了和方案2对齐,每次也只运2个人);

2.最轻和次轻的过去,然后最轻的回来让最重的两个过去,次轻的在那边把船再开回来。一共运过去了2个人。

这样一来,人数少于4的时候要么只有最轻的3个人,要么只有最轻的2个人。如果还剩3个人,就让最轻的每次带一个;如果还剩2个人,就直接两个人过河了。

c++代码来自 寒冰-侠客

---

 

 

--

4比例问题

输入例子1:

1 1 2 1

输出例子1:

0 0

输入例子2:

1000 500 4 2

输出例子2:

1000 500

输入例子3:

1000 500 3 1

输出例子3:

999 333
#include<iostream>
#include<vector>
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
typedef unsigned int u8;
ll A,B,a,b;

int MaxFactor(ll a,ll b)
{
    ll c=b;
    while(a%b!=0)
    {
        c=a%b;
        a=b;
        b=c;
    }
    return c;
}

int main()
{
    cin>>A>>B>>a>>b;
    int MaxCom=MaxFactor(a,b);
    int simp_a=a/MaxCom,simp_b=b/MaxCom;
    int k;
    if((b*A)/(a*B)) k=B/simp_b;
    else k=A/simp_a;
    u8 x=k*simp_a;
    u8 y=k*simp_b;
    cout<<x<<" "<<y<<endl;
    return 0;
}

 

5小强修水渠

输入例子1:

4
0 0
0 50
50 50
50 0

输出例子1:

100

例子说明1:

当修建水渠位置的直线方程为x=0或者x=50时,都能获得最小距离和.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

//1.题目的答案其实和x轴的坐标无关系,只需要考虑y轴的数据;
//2.在输入数据的时候,是先输入的y,再输入x;
//3.假如只有两座房子,它们在y方向的距离为length,水渠只要在这两个端点之间(包括端点),所得到的距离总和就是最短的,
//为length,如果水渠在两个端点之外,那就不行;

//4.对所有的纵坐标从小到大排序,把最外侧的两个点找出来,它俩到水渠的距离之和为(y[n-1] - y[0]),水渠在它俩之间;
//接着考虑第2个数和倒数第2个数,水渠应该调整到它俩之间去,这样它俩到水渠的距离之和为(y[n-2] - y[1]);
//水渠的位置调整后,并不违背之前所做的工作,因为水渠的位置还是在第1个值和最后那个值之间;
//同理考虑第3组,。。。。这一步完成后,水渠的位置在第3组数之间,同样在第2组数之间,因为第3组数在第2组数的内侧

//5.最后的结果要把所有的差值加起来,注意要声明为long long类型;
//6.每次操作的是两个数,如果数的总数是奇数个呢?最中间那个可以不考虑,因为可以把水渠选在这个值上
void solve(int n)
{
    vector<int> nums(n, 0);
    for (int i = 0; i < n; ++i)
    {
        int x = 0;
        cin >>  nums[i] >> x; //先输入y,再输入的x,真是干tn的
    }
    sort(nums.begin(), nums.end()); //排序
    int p1 = 0;
    int p2 = n - 1;
    long long ans = 0;
    while(p1 < p2) //从两端往中间收缩
    {
        ans += nums[p2] - nums[p1]; //保存一组结果
        ++p1;
        --p2;
    }
    cout << ans << endl;
}


int main()
{
    int n = 0;
    cin >> n;
    solve(n);
    return 0;
}

 

6国际交流会

输入例子1:

4
3 6 2 9

输出例子1:

20
6 2 9 3

例子说明1:

这么坐的话
差异和为|6-2|+|2-9|+|9-3|+|3-6|=20为最大的情况。

输入例子1:

5
5 9 5 4 4
4 7 4 10 3
2 10 9 2 3

输出例子1:

5

例子说明1:

数组b可以为[5,7,5,4,4],答案为5。
#include<iostream>
#include<algorithm>
#include<vector>
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
ll Abs(ll a,ll b)
{
    if(a>=b) return a-b;
    else return b-a;
}
int main()
{
    ios::sync_with_stdio(false),cin.tie(0);
    int n,p1,p2,index;
    ll ans=0;
    cin>>n;
    ll a[n];
    vector<ll> tmp;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    sort(a,a+n); //smaller--->larger
    if(n%2==0) p2=n/2;
    else p2=n/2+1;
    p1=0;//最左边
    index=p2;//中间
    while(p1<index && p2<n)
    {//从最左边和最中间,向右移动
        tmp.push_back(a[p1]);
        p1+=1;
        tmp.push_back(a[p2]);
        p2+=1;
    }
    if(p1<index) tmp.push_back(a[p1]);
    for(int i=0;i<n-1;i++) 
    {
        ans+=Abs(tmp[i],tmp[i+1]);
    }
    ans+=Abs(tmp[0],tmp[n-1]);
    cout<<ans<<endl;
    for(int i:tmp) 
    {
        cout<<i<<" ";
    }
    cout<<endl;
    return 0;
}

 

7小强的神奇矩阵

#include <iostream>
#include <vector>
using namespace std;
void solution(int n)
{
    vector<vector<int>> nums(3,vector<int>(n, 0));
    for (int i = 0; i < 3; ++i) 
        for (int j = 0; j < n; ++j) 
            cin >> nums[i][j];//读数据
    
    vector<vector<long long>> dp(3, vector<long long>(n, 0));

    for (int j = 1; j < n; ++j) {
        for (int i = 0; i < 3; ++i) {
            //分别取0、1、2行的时候,值是多少。
	       //当它减去nums[0][j-1]的时候,就要继承dp[0][j-1]这个状态。
            long long f1 = abs(nums[i][j] - nums[0][j - 1]) + dp[0][j - 1];
            long long f2 = abs(nums[i][j] - nums[1][j - 1]) + dp[1][j - 1];
            long long f3 = abs(nums[i][j] - nums[2][j - 1]) + dp[2][j - 1];//状态
            dp[i][j] = min(min(f1, f2), f3);//状态
        }
    }
    cout << min(min(dp[0][n - 1], dp[1][n - 1]), dp[2][n - 1]) << endl;
}

int main()
{
    int n = 0;
    cin >> n;
    solution(n);
    return 0;
}

 

8蚂蚁森林之王

输入例子1:

4
0 1 1 1

输出例子1:

4
1
1
1

例子说明1:

如果第 2,3,4 只小动物均和第一只投一样的票,则第一只小动物可以获得四票。
#include<iostream>
#include<vector>

using namespace std;
void func(){
    int n;
    cin>>n;
    vector<int> A(n+1);
    vector<int> num(n+1,1);//全是1
    for(int i=1;i<=n;i++){
        cin>>A[i];
    }
    for(int i=n;i>=1;i--){//最多得到能力相同的票
       num[A[i]] += num[i];//和崇拜的对象投相同票
    }
    for(int i=1;i<=n;i++){//每个人最多几票。
        cout<<num[i]<<endl;//最弱只可能自己1票
    }
}
int main(){
    func();
    return 0;
}

9删除字符

输入例子1:

2
5 2
abcab
10 4
lkqijxsnny

输出例子1:

aab
ijsnny

同样是大佬零葬的解答:

要想字典序小,那么字符串中的字母应该尽可能满足升序。因此只需遵循一个原则,当前字母的ASCII码不能比前面字母的小,如果出现这种情况,就要把前面的字母删除掉,从当前字母重新开始算字符串。最后需要注意,返回的字符串长度应该为n-m。

#include<bits/stdc++.h>
using namespace std;

int main(){
    int T;
    cin>>T;
    while(T--){
        int n,m;
        cin>>n>>m;
        string in;
        cin>>in;
        stack<char> tmp;
        int deleteNumber = 0;
        for (int i = 0;i<in.length();i++){
            char x = in[i];
            //当前的x小于栈顶,则弹出栈顶。如果还小,则再弹出栈顶。
            while(!tmp.empty() && x<tmp.top() && deleteNumber<m){
                tmp.pop();
                deleteNumber++;
            }
            tmp.push(x);
        }
        string result;
        while(!tmp.empty()){
            result+=tmp.top();//栈内元素倒出来。
            tmp.pop();
        }
        reverse(result.begin(),result.end());//反向
        cout<<result.substr(0,n-m)<<endl;//输出
    }
    return 0;
}

10视力表

输入例子1:

2 3 1 0 0

输出例子1:

4

例子说明1:

共有如下四种情况

上上    上上

上下    下上

上下    下上

上上    上上

输入例子2:

2 2 1 1 0

输出例子2:

12

输入例子3:

2 1 1 1 1

输出例子3:

24

这道题通过暴力法能通过。

#include<iostream>
#include<cmath>
#include<string>
#include<cstring>
#include<vector>
#include<map>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include <cstdlib>
#include <climits>
#include <ctype.h>
#include<functional>
using namespace std;
const int maxn = 1e5 + 5;
typedef long long int ll;
int n, a, b, c, d;
const int MOD = 998244353;
ll f[maxn], inv[maxn];//f存储i阶乘,inv存储(i阶乘)的逆元
//
ll Pow(ll x, ll t)
{
	ll cnt = 1;
	while (t)
	{
		if (t & 1)//x&1是判断x是奇数还是偶数,如果x是奇数那么x&1的值就是true,如果x是偶数那么x&1的值就是false
			cnt = cnt*x%MOD;
		x = x * x %MOD;
		t >>= 1;
	}
	return cnt;
}

void init()
{
	cin >> n >> a >> b >> c >> d;
	n = n*n;
	f[0] = 1;
	for (int i = 1;i <= n;i++)
		f[i] = i*f[i - 1] % MOD;

	//a的逆元 = a^(p-2) mod p 
	inv[0] = 1;
	inv[n] = Pow(f[n], MOD - 2);
	//inv[i]=inv[i+1]*(i+1)
	for (int i = n-1;i >= 1;i--)
		inv[i] = inv[i + 1] * (i + 1) % MOD;
}

int main()
{
	init();
	ll ans = f[n];
	//cout << f[n] << ' ' << inv[a] << ' ' << inv[b] << ' ' << inv[c] << ' ' << inv[d] << '\n';
	//for (int i = n;i >= 1;i--)
	//	cout << inv[i] << ' ';
	//cout << endl;
	ans = ans*inv[a] % MOD;
	ans = ans*inv[b] % MOD;
	ans = ans*inv[c] % MOD;
	ans = ans*inv[d] % MOD;
	cout << ans << '\n';
}
/*
3 7 1 0 1
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值