【网易校招2019笔试真题】

1. 俄罗斯方块

时间限制:1秒

空间限制:262144K

小易有一个古老的游戏机,上面有着经典的游戏俄罗斯方块。因为它比较古老,所以规则和一般的俄罗斯方块不同。
荧幕上一共有 n 列,每次都会有一个 1 x 1 的方块随机落下,在同一列中,后落下的方块会叠在先前的方块之上,当一整行方块都被占满时,这一行会被消去,并得到1分。
有一天,小易又开了一局游戏,当玩到第 m 个方块落下时他觉得太无聊就关掉了,小易希望你告诉他这局游戏他获得的分数。
 

输入描述:

第一行两个数 n, m
第二行 m 个数,c1, c2, ... , cm , ci 表示第 i 个方块落在第几列
其中 1 <= n, m <= 1000, 1 <= ci <= n


 

输出描述:

小易这局游戏获得的分数

输入例子1:

3 9
1 1 2 2 2 3 1 2 3

输出例子1:

2
#include<iostream>
#include <vector>
using namespace std;

vector<int> core;

int main()
{
	int n, m;
	cin >> n >> m;
	core.resize(n);

	for (int i = 0; i < m; i++)
	{
		int C;
		cin >> C;
		core[C-1]++;
	}
	int min_ = m;
	for (int i = 0; i < n; i++)
		if (core[i] < min_)
			min_ = core[i];
	cout << min_;
}

2.丰收

时间限制:1秒

空间限制:262144K

又到了丰收的季节,恰逢小易去牛牛的果园里游玩。
牛牛常说他对整个果园的每个地方都了如指掌,小易不太相信,所以他想考考牛牛。
在果园里有N堆苹果,每堆苹果的数量为ai,小易希望知道从左往右数第x个苹果是属于哪一堆的。
牛牛觉得这个问题太简单,所以希望你来替他回答。
 

输入描述:

第一行一个数n(1 <= n <= 105)。
第二行n个数ai(1 <= ai <= 1000),表示从左往右数第i堆有多少苹果
第三行一个数m(1 <= m <= 105),表示有m次询问。
第四行m个数qi,表示小易希望知道第qi个苹果属于哪一堆。


 

输出描述:

m行,第i行输出第qi个苹果属于哪一堆。

输入例子1:

5
2 7 3 4 9
3
1 25 11

输出例子1:

1
5
3

 注意:

1.此题必须用二分查找才能通过,编程时注意二分查找的区间设置。

2.引用函数时一定要传递实参(加入&),形参传入函数,相当于copy了一个镜像会增加计算耗时。

#include<iostream>
#include <vector>
using namespace std;

vector<int> core;
//二分查找 
/******************************************
输入:数组a,数字b
输出:数字在数组的第几个位置内 
如  2 5 7 9  ,2
    1
******************************************/
int div(vector<int> &a, int &b)
{
	int n = a.size();

	if (a[0] >= b)
		return 1;
	else if (b > a[n - 1])
		return -1;

	int min_ = 0, max_ = n - 1;
	while (min_<max_)
	{
		int temp = (min_ + max_) / 2;
		//cout << "min,max,temp=" << min_+1 << "," << max_+1 <<","<< temp+1<< endl;
		if (a[temp] == b)
			return temp + 1;
		else if (a[temp + 1] == b)
			return temp + 2;
		else if (a[temp] < b && a[temp + 1] > b)
			return temp + 2;

		if (a[temp] < b)
			min_ = temp;
		else
			max_ = temp;
	}
  return -1;
}


int main()
{
	int n, m;
	cin >> n;
	if (n == 1)
	{
		cout << "1";
		return 0;
	}

	core.resize(n);
	for (int i = 0; i <n; i++)
	{

		int C;
		cin >> C;
		if (i == 0)
			core[i] = C;
		else
			core[i] = core[i - 1] + C;
		//cout << " " << core[i];
	}
	cin >> m;

	for (int i = 0; i <m; i++)
	{

		int C;
		cin >> C;
		cout << div(core, C) << endl;
	}
	return 0;

}

3..整理房间

链接:https://www.nowcoder.com/questionTerminal/c32f4c74446541a1ad2abbe54476681f
来源:牛客网
 

又到了周末,小易的房间乱得一团糟。

他希望将地上的杂物稍微整理下,使每团杂物看起来都紧凑一些,没有那么乱。

地上一共有n团杂物,每团杂物都包含4个物品。第i物品的坐标用(a i,b i)表示,小易每次都可以将它绕着(x i,y i)逆时针旋转,这将消耗他的一次移动次数。如果一团杂物的4个点构成了一个面积不为0的正方形,我们说它是紧凑的。

因为小易很懒,所以他希望你帮助他计算一下每团杂物最少需要多少步移动能使它变得紧凑。

输入描述:

第一行一个数n(1 <= n <= 100),表示杂物的团数。
接下来4n行,每4行表示一团杂物,每行4个数a i,b i, x i,y i,( -  10 4  <= x i,y i,a i,b i  <= 10 4),表示第i个物品旋转的它本身的坐标和中心点坐标。


 

输出描述:

Ñ行,每行1个数,表示最少移动次数。

示例1

输入

4
1 1 0 0
-1 1 0 0
-1 1 0 0
1 -1 0 0
1 1 0 0
-2 1 0 0
-1 1 0 0
1 -1 0 0
1 1 0 0
-1 1 0 0
-1 1 0 0
-1 1 0 0
2 2 0 1
-1 0 0 -2
3 0 0 -2
-1 1 -2 0

输出

1
-1
3
3

说明

对于第一团杂物,我们可以旋转第二个或者第三个物品1次。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
    int n;
    cin >> n;
    for (int i = 0; i != n; ++i) {
        vector<vector<pair<int, int>>>edge(4, vector<pair<int, int>>(4, { 0,0 }));
        for (int j = 0; j != 4; ++j) {
            int a, b, x, y;
            cin >> a >> b >> x >> y;
            edge[j][0] = { a,b };
            for (int k = 1; k != 4; ++k)
                edge[j][k] = { x + y - edge[j][k - 1].second,y - x + edge[j][k - 1].first };
        }
        int mincost = 0x7FFFFFFF;
        for (int a = 0; a != 4; ++a)
            for (int b = 0; b != 4; ++b) 
                for (int c = 0; c != 4; ++c) 
                    for (int d = 0; d != 4; ++d) {
                        vector<pair<int, int>>temp{ edge[0][a],edge[1][b],edge[2][c],edge[3][d] };
                        sort(temp.begin(), temp.end());
                        if (temp[1].second - temp[0].second != 0&&
                            temp[1].second - temp[0].second == temp[2].first - temp[0].first&&
                            temp[3].second - temp[2].second == temp[2].first-temp[0].first&&
                            temp[3].second - temp[1].second == temp[1].first-temp[0].first)
                            mincost = min(mincost, a + b + c + d);
                    }
        cout << (mincost == 0x7FFFFFFF ? -1 : mincost) << endl;
    }
    return 0;
}

4.表达式求值

链接:https://www.nowcoder.com/questionTerminal/3e483fe3c0bb447bb17ffb3eeeca78ba
来源:牛客网
 

今天上课,老师教了小易怎么计算加法和乘法,乘法的优先级大于加法,但是如果一个运算加了括号,那么它的优先级是最高的例如:

1

2

3

4

1+2*3=7

1*(2+3)=5

1*2*3=6

(1+2)*3=9

现在小易希望你帮他计算给定3个数a,b,c,在它们中间添加“+”,“*”,“(”,“)”符号,能够获得的最大值。

输入描述:

一行三个数a,b,c(1 <= a,b,c <= 10)


 

输出描述:

能够获得的最大值

示例1

输入

1 2 3

输出

9

思路:

先排个序。

然后满足最小的两个值之和小于最大的值且最小值为1时,结果为(min+mid)*max,

否则结果为min*mid*max。

#include <iostream>
#include <vector>
  
using namespace std;
  
double max1(double a, double b) {
    return max(a + b, a * b);
}
  
double max2(double a, double b, double c) {
    return max(max1(max1(a, b), c), max1(a, max1(b, c)));
}
  
int main() {
    double a = 0;
    double b = 0;
    double c = 0;
    while (cin >> a >> b >> c) {
        cout << max2(a, b, c) << endl;
    }
    return 0;
}

5.塔

链接:https://www.nowcoder.com/questionTerminal/54868056c5664586b121d9098d008719
来源:牛客网
 

小易有一些立方体,每个立方体的边长为1,他用这些立方体搭了一些塔。

现在小易定义:这些塔的不稳定值为它们之中最高的塔与最低的塔的高度差。

小易想让这些塔尽量稳定,所以他进行了如下操作:每次从某座塔上取下一块立方体,并把它放到另一座塔上。

注意,小易不会把立方体放到它原本的那座塔上,因为他认为这样毫无意义。

现在小易想要知道,他进行了不超过k次操作之后,不稳定值最小是多少。

输入描述:

第一行两个数n,k (1 <= n <= 100, 0 <= k <= 1000)表示塔的数量以及最多操作的次数。
第二行n个数,ai(1 <= ai <= 104)表示第i座塔的初始高度。


 

输出描述:

第一行两个数s, m,表示最小的不稳定值和操作次数(m <= k)
接下来m行,每行两个数x,y表示从第x座塔上取下一块立方体放到第y座塔上。

示例1

输入

3 2
5 8 5

输出

0 2
2 1
2 3
链接:https://www.nowcoder.com/questionTerminal/54868056c5664586b121d9098d008719
来源:牛客网

#include<iostream>
using namespace std;
int main(){
    int n,k,tempInt;
    int s;
    cin>>n>>k;
    int a[n][2],m[k][2];
    for(int i=0;i<n;i++){
        cin>>a[i][0];
        a[i][1]=i+1;
    }
//数据输入完毕
    //计算数据输出,即不稳定度s和最小操作次数m
    //最大操作次数k,每次操作必定是由最高塔移到最低塔最合算
    //每次操作前后输入输出数据的类型不变
    //每次操作前进行如下判断:
    //如果最大值最小值两者相差小于2,此时停止操作   
    //否则每次操作对不稳定度的影响分为3种情况:
    //1.最大值和最小值唯一,此时s-2
    //2.最大值和最小值其中仅有一个不唯一,此时s-1
    //3.最大值和最小值都不唯一,此时s-0
    /*****************************改进算法*****************************/
    //每次操作前先统计出最大值和最小值集合,然后以最大值和最小值之差作为结束操作的一个判断参数(另一个判断参数为k)
    //最大值(maxSet)最小值(minSet)集合中的元素个数差,将作为s参数的更新依据,同时也是更新最大值最小值集合的依据
    //min{|maxSet|,|minSet|}将作为更新m参数的依据
    //****************************进一步改进*********************************
    //每次计算最大最小值集合都要遍历数组将是十分耗时的,所以不妨对塔高进行排序,这在k>n时比较有用
    //采用while循环,每次开始前进行判断与s参数以及m参数的更新
    //****************************冒泡排序a[n][2]从小到大排序************************************
    for(int i=0;i<n-1;i++){
        for(int j=0;j<n-1-i;j++){
            if(a[j][0]>a[j+1][0]){
                tempInt=a[j][0];
                a[j][0]=a[j+1][0];
                a[j+1][0]=tempInt;
                tempInt=a[j][1];
                a[j][1]=a[j+1][1];
                a[j+1][1]=tempInt;
            }
        }
    }
    //****************************进行操作以及更新s和m参数*************************************
    s=0;
    int minCount,maxCount,opNum;
    while(s<k&&(a[n-1][0]-a[0][0])>=2){
        minCount=1;
        while(minCount<n&&a[minCount][0]==a[0][0])minCount++;
        maxCount=1;
        while(maxCount<n&&a[n-1-maxCount][0]==a[n-1][0])maxCount++;
        opNum=(maxCount<minCount)?maxCount:minCount;
        if(s+opNum>k)break;
        //记录操作
        for(int j=0;j<opNum;j++){
            (a[minCount-1-j][0])++;
            (a[n-maxCount+j][0])--;
            m[s+j][0]=a[n-maxCount+j][1];
            m[s+j][1]=a[minCount-1-j][1];
        }
        s+=opNum;
    }
    cout<<(a[n-1][0]-a[0][0])<<' '<<s<<endl;
    for(int j=0;j<s;j++){
        cout<<m[j][0]<<' '<<m[j][1]<<endl;
    }
    return 0;
}

6.小易的字典

链接:https://www.nowcoder.com/questionTerminal/12b1b8ef17e1441f86f322b250bff4c0
来源:牛客网
 

小易在学校中学习了关于字符串的理论, 于是他基于此完成了一个字典的项目。

小易的这个字典很奇特, 字典内的每个单词都包含n个'a'和m个'z', 并且所有单词按照字典序排列。

小易现在希望你能帮他找出第k个单词是什么。

输入描述:

 

输入包括一行三个整数n, m, k(1 <= n, m <= 100, 1 <= k <= 109), 以空格分割。


 

输出描述:

输出第k个字典中的字符串,如果无解,输出-1。

示例1

输入

2 2 6

输出

zzaa

说明

字典中的字符串依次为aazz azaz azza zaaz zaza zzaa

链接:https://www.nowcoder.com/questionTerminal/12b1b8ef17e1441f86f322b250bff4c0
来源:牛客网
 

排列组合,n个'a'和m个'z',只能组成$C_{n+m}^n$,记为count(n+m,n) 个单词。

思路:

  1. 假设第一个字符为a,则剩下n-1个'a'和m个'z'组成的子序列只能构成count(n-1+m,n-1)个单词,且是字典中前count(n-1+m,n-1)个单词。
  2. 比较k和count(n-1+m,n-1),若k小,说明k是前count(n-1+m,n-1)个单词,则第一个字符必为'a'。子问题化为在子序列(n-1个'a'和m个'z')找到第k个单词
  3. 若k大,则说明第一个字符必为'z',单词是以'z'开头的单词中的第k-count(n-1+m,n-1)个。子问题化为在子序列(n个'a'和m-1个'z')找到第k-count(n+m-1,m-1)个单词。

eg:n=2,m=2,k=5

  1. 假设第一个字符为a,则剩下1个a,2个z只能构成3个单词,且是字典中前3个单词(aamm,amam,amma)
  2. k>3,则第一个字符必为z。原问题化为在n=2,m=1,k=2,即在剩下2个a,1个z中找到第2个单词
链接:https://www.nowcoder.com/questionTerminal/12b1b8ef17e1441f86f322b250bff4c0
来源:牛客网

#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
    void solve(int n, int m, long long k) {
        vector<char> x;//
        while (n && m) {
            //每次迭代问题规模缩减一个单位
            ////排列组合:假设当前序列首字符为a,剩下n-1个a放在剩下n - 1 +m 个位置共有的可能数
            long long count = 1;
            for (int i = 0; i < n - 1; i++) {//求组合数
                count *= n - 1 + m - i;
                count /= (i + 1);
                if (count > k)break;//防止越界。count>k就可以退出计算了
            }
            if (k <= count) {//如果k小于等于count,则表明首字符的确应为a
                x.push_back('a');
                n--;//问题缩减为 n-1个a和m个z 中找第k大
            }
            else {
                x.push_back('z');
                m--;//问题缩减为 n-1个a和m个z 中找第k-count大
                k -= count;
            }
        }
        //循环结束后,剩余子序列只存在"aa..aaa" 或 "zz..zzz"1种情况
        if (k != 1) {//
            cout << -1;
            return;
        }
        while (n--)x.push_back('a');
        while (m--)x.push_back('z');
        for (int i = 0; i < x.size(); i++) {
            cout << x[i];
        }
    }
};
int main() {
    Solution a;
    int n, m;
    long long k;
    while (cin >> n >> m >> k) {
        a.solve(n, m, k);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34570910/article/details/82557167
今日推荐