牛客网2017年校招全国统一模拟笔试(第一场)编程题集合


layout: post
title: 牛客网2017年校招全国统一模拟笔试(第一场)编程题集合
date: 2017-05-27
tag: oj

目录

  • TOC
    {:toc}

好多鱼!

牛牛有一个鱼缸。鱼缸里面已经有n条鱼,每条鱼的大小为fishSize[i] (1 ≤ i ≤ n,均为正整数),牛牛现在想把新捕捉的鱼放入鱼缸。鱼缸内存在着大鱼吃小鱼的定律。经过观察,牛牛发现一条鱼A的大小为另外一条鱼B大小的2倍到10倍(包括2倍大小和10倍大小),鱼A会吃掉鱼B。考虑到这个,牛牛要放入的鱼就需要保证:
1、放进去的鱼是安全的,不会被其他鱼吃掉
2、这条鱼放进去也不能吃掉其他鱼
鱼缸里面已经存在的鱼已经相处了很久,不考虑他们互相捕食。现在知道新放入鱼的大小范围[minSize,maxSize](考虑鱼的大小都是整数表示),牛牛想知道有多少种大小的鱼可以放入这个鱼缸。 

输入描述:

输入数据包括3行.
第一行为新放入鱼的尺寸范围minSize,maxSize(1 ≤ minSize,maxSize ≤ 1000),以空格分隔。

第二行为鱼缸里面已经有鱼的数量n(1 ≤ n ≤ 50)

第三行为已经有的鱼的大小fishSize[i](1 ≤ fishSize[i] ≤ 1000),以空格分隔。


输出描述:

输出有多少种大小的鱼可以放入这个鱼缸。考虑鱼的大小都是整数表示

输入例子:

1 12
1
1

输出例子:

3

AC代码

#include<iostream>
using namespace std;
int a[55]; int mi,ma;
int n; int main(){
    cin >> mi >> ma;
    cin >> n;
    for(int i = 0; i < n; i++)
        cin >> a[i];
    int ans = 0;
    for(int i = mi; i <= ma; i++){
        int flag = 1;
        for(int j = 0; j < n; j++){
            if( (i >= a[j] * 2 && i <= a[j] * 10) || (i * 2 <= a[j] && i * 10 >= a[j]) ){  //吃和被吃的规则
                flag = 0;
            }
        }
        if(flag)
            ans++;
    }
    cout << ans << endl;  //不需要考虑新放入的鱼之间会互相吃掉
}

循环单词

如果一个单词通过循环右移获得的单词,我们称这些单词都为一种循环单词。 例如:picture 和 turepic 就是属于同一种循环单词。 现在给出n个单词,需要统计这个n个单词中有多少种循环单词。 
输入描述:

输入包括n+1行:

第一行为单词个数n(1 ≤ n ≤ 50)

接下来的n行,每行一个单词word[i],长度length(1 ≤ length ≤ 50)。由小写字母构成


输出描述:

输出循环单词的种数

输入例子:

5
picture
turepic
icturep
word
ordw

输出例子:

2

思路分析

  • 数据量比较小,就使用了STL的Map来实现,将每个字符串的所有循环形式存起来,每次有新的字符串时先判断是否已经存在,如果已经存在则统计结果+1,否则将其所有循环形式进行存储

AC代码

#include<iostream>
#include<map>
#include<string>
using namespace std;
 
int n;
map<string, int> mp;
 
int main() {
    while (scanf("%d", &n) != EOF) {
        string s, tem;
        int ans = 0;
        for (int i = 0; i < n; i++) {
            cin >> s;
            if (mp[s] == 0) //表示一个新的字符串
                ans++;
            for (int j = 0; j < s.length(); j++) {
                tem = s.substr(j, s.length() - j) + s.substr(0, j);  //substr参数1-off,参数2-Count
                mp[tem] = 1;
            }
        }
        cout << ans << endl;
    }
    return 0;
}
添加笔记

DNA合成

DNA分子是以4种脱氧核苷酸为单位连接而成的长链,这4种脱氧核苷酸分别含有A,T,C,G四种碱基。碱基互补配对原则:A和T是配对的,C和G是配对的。如果两条碱基链长度是相同的并且每个位置的碱基是配对的,那么他们就可以配对合成为DNA的双螺旋结构。现在给出两条碱基链,允许在其中一条上做替换操作:把序列上的某个位置的碱基更换为另外一种碱基。问最少需要多少次让两条碱基链配对成功 
输入描述:

输入包括一行:
包括两个字符串,分别表示两条链,两个字符串长度相同且长度均小于等于50。


输出描述:

输出一个整数,即最少需要多少次让两条碱基链配对成功

输入例子:

ACGT TGCA

输出例子:

0

思路分析

  • 接统计下标相同的位置上匹配的内容,如果匹配则+1,最后用总长度-匹配长度即可

AC代码

#include <iostream>
#include <string>
 
using namespace std;
 
int main()
{
    string str1, str2;
    int count = 0;
 
    while (cin>>str1>>str2)
    {
        for (int i = 0; i < str1.length(); i++)
        {
            if (str1[i]=='A'&&str2[i]=='T')
            {
                count++;
            }
            if (str1[i]=='C'&&str2[i]=='G')
            {
                count++;
            }
            if (str1[i]=='T'&&str2[i]=='A')
            {
                count++;
            }
            if (str1[i]=='G'&&str2[i]=='C')
            {
                count++;
            }
        }
        cout << (str1.length()-count);
    }
    return 0;
}

连续整数

牛牛的好朋友羊羊在纸上写了n+1个整数,羊羊接着抹除掉了一个整数,给牛牛猜他抹除掉的数字是什么。牛牛知道羊羊写的整数神排序之后是一串连续的正整数,牛牛现在要猜出所有可能是抹除掉的整数。例如:
10 7 12 8 11 那么抹除掉的整数只可能是9
5 6 7 8 那么抹除掉的整数可能是4也可能是9

输入描述:

输入包括2行:

第一行为整数n(1 <= n <= 50),即抹除一个数之后剩下的数字个数

第二行为n个整数num[i] (1 <= num[i] <= 1000000000)


输出描述:

在一行中输出所有可能是抹除掉的数,从小到大输出,用空格分割,行末无空格。如果没有可能的数,则输出mistake

输入例子:

2
3 6

输出例子:

mistake

AC代码

  • 边界条件的判断
#include <iostream>
#include <vector>
#include<algorithm>
 
using namespace std;
 
int main()
{
    int N;
    int num;
    vector<int> vec;  //1 <= num[i] <= 1000000000  正整数
 
    while (cin >> N)
    {
        for (int i = 0; i < N; i++)
        {
            cin >> num;
            vec.push_back(num);
        }
 
 
        if (N == 1 && vec[0] != 1)
        {
            cout << vec[0] - 1 <<' '<< vec[0] + 1;
            break;
        }
        if (N == 1 && vec[0] == 1)
        {
            cout << vec[0] + 1;
            break;
        }
 
        sort(vec.begin(), vec.end());
 
        int count = 0;
        int count1 = 0;
        int pos = 0;
        for (int i = 1; i < N; i++)
        {
            num = vec[i] - vec[i - 1];
 
            if (num == 2)
            {
                pos = i;
                count++;
            }
            if (num == 1)
            {
                count1++;
            }
        }
        if (count == 1 && ((count + count1) == N - 1))
        {
            cout << vec[pos] - 1;
        }
        else if (count1 == N - 1&&vec[0]==1)
        {
            cout<<vec[N-1]+1;
        }
        else if (count1 == N - 1)
        {
            cout << vec[0] - 1 <<' '<< vec[N - 1] + 1;
        }
        else
        {
            cout << "mistake";
        }
    }
 
    return 0;
}
 
//测试用例:
//4
//5 2 1 2
//
//对应输出应该为 :
//
//      mistake
//
//  你的输出为 :
//
//mistake06
 
//测试用例:
//1
//166
//
//对应输出应该为 :
//
//      165 167
//
//  你的输出为 :
//
//        167
 
//测试用例:
//1
//1
//
//对应输出应该为 :
//
//      2

超级素数幂

如果一个数字能表示为p^q(^表示幂运算)且p为一个素数,q为大于1的正整数就称这个数叫做超级素数幂。现在给出一个正整数n,如果n是一个超级素数幂需要找出对应的p,q。 
输入描述:

输入一个正整数n(2 ≤ n ≤ 10^18)


输出描述:

如果n是一个超级素数幂则输出p,q,以空格分隔,行末无空格。
如果n不是超级素数幂,则输出No

输入例子:

27

输出例子:

3 3

思路分析

  • 我们首先计算出top=Log(n)/log(2),这里的top就是q所能取得到的最大值,然后我们从2开始枚举到top,每次计算i次根号n,在其为素数的情况下计算i次根号n的i次方是否为n,如果是则输出,否则计算下一次,如果一直计算到top都没有的话则输出No

AC代码

#include<iostream>
#include <cmath>
using namespace std;
 
bool isprime(long long N)
{
    for (long long i = 2; i <= sqrt(N);i=i+1)
    {
        if (N%i==0)
        {
            return false;
        }
    }
    return true;
}
 
 
long long Get_basep_q(long long p,long long q)  //求p的q次幂,直接用pow,AC不过
{
    long long ret = 1;
    long long temp = p;
    while (q)
    {
        if (q%2==1)  //q为偶数最后进判断,q为奇数
        {
            ret *= temp;
        }
        temp = temp*temp;
        q /= 2;
    }
    return ret;
}
 
//p的q次幂
int main()
{
    long long N;
    while (cin>>N)
    {
        long long maxq = log10(N) / log10(2);
        bool flag = false;
        for (long long i = 2; i <= maxq;i++)
        {
            long long basep = pow(N,1.0/i);
            if (isprime(basep))
            {
                long long sum =Get_basep_q(basep,i);
                if (sum==N)
                {
                    cout << basep << ' ' << i;
                    flag = true;
                    break;
                }
            }
        }
        if (flag==false)
        {
            cout << "No" << endl;
        }
    }
}

序列和

给出一个正整数N和长度L,找出一段长度大于等于L的连续非负整数,他们的和恰好为N。答案可能有多个,我我们需要找出长度最小的那个。
例如 N = 18 L = 2:
5 + 6 + 7 = 18 
3 + 4 + 5 + 6 = 18
都是满足要求的,但是我们输出更短的 5 6 7

输入描述:

输入数据包括一行:
两个正整数N(1 ≤ N ≤ 1000000000),L(2 ≤ L ≤ 100)


输出描述:

从小到大输出这段连续非负整数,以空格分隔,行末无空格。如果没有这样的序列或者找出的序列长度大于100,则输出No

输入例子:

18 2

输出例子:

5 6 7

AC代码

  • 等差数列求和问题
#include<iostream>
using namespace std;
 
int main()
{
    int N, L;
    while (cin>>N>>L) //长度为L的等差数列求第一项
    {
        bool flag = false;
        for (int i = L; i <= 100;i++)
        {          
            if ((2 * N - i*i + i) % (2 * i)==0)
            {
                int a1 = (2 * N - i*i + i) / (2 * i); //首项
                for (int j = 0; j < i;j++)
                {
                    if (j==0)
                    {
                        cout << a1;
                    }
                    else
                    {
                        cout <<' '<< a1 + j;
                    }
                }
                flag = true;
                break;
            }
        }
        if (flag==false)
        {
            cout << "No" << endl;
        }
    }
    return 0;
}

页码统计

牛牛新买了一本算法书,算法书一共有n页,页码从1到n。牛牛于是想了一个算法题目:在这本算法书页码中0~9每个数字分别出现了多少次? 
输入描述:

输入包括一个整数n(1 ≤ n ≤ 1,000,000,000)


输出描述:

输出包括一行10个整数,即0~9这些数字在页码中出现的次数,以空格分隔。行末无空格。

输入例子:

999

输出例子:

189 300 300 300 300 300 300 300 300 300

思路分析

从1~9这9个数字的计算我们可以找到如下规律(以下除0以外全部以1为基数) 
(1)当这一位比要找的数字大时:直接求(高位+1)*base 
例如12213中,我们找百位的1,则百位出现1的情况为100~199,1100~1199,2100~2199,…..,11100~11199,12100~12199,一共1300个,刚到等于高位数字+1再乘以当前位数,即(12+1)*100; 
(2)当这一位比要找的数字小时:直接求(高位)*base 
例如12013中,我们找百位的1,则百位出现1的情况为100~199,1100~1199,2100~2199,…..,11100~11199,一共1200个,刚到等于高位数字再乘以当前位数,即12*100; 
(3)当这一位等于要找的数字时: 
例如12113中,我们找百位的1,则百位出现1的情况为100~199,1100~1199,2100~2199,…..,11100~11199,12100~12199,一共1200个,刚到等于高位数字再乘以当前位数,即12*100;除了这些数字以外,还有12100~12113这14个数字,即低位数+1,即13+1.

举个栗子: 
对统计1~785012中5出现的个数 
我们先考虑5在低位第三位出现的次数,我们就将第三位固定为5:XXX5XX。 
此时,问题就转化为,“X”处一共有多少种组合方式。 
高位的3位可以从000到785之间,低位的2位可以从00到99之间。 
但是,当高3位为785时,7855XX无论如何都超过了785012,因此,高三位可以选择的只有000~784(共785个数字),高三位和低二位一共有785*100种组合方式。

我们再考虑5在低位第四位出现的次数,我们就将第四位固定为5:XX5XXX。 
与前面相同,高位的二位可以从00到78之间,低位的三位可以从000到999之间。 
当高位是00到77时,与前面一种情况是相同的,一共可以组合出78*1000种情况。 
当高位是78时,785XXX就有超过785012的可能了,后三位的选择局限在000到012之间,共13中情况。 
两者结合就是:78*1000+13

最后考虑5在低位第5位出现的次数,我们就将第五位固定为5:X5XXXX。 
与前面相同,最高位可以从0取到7,低四位可以从0000取到9999. 
当最高位为0到6时,与第一种情况相同,一共可以组合出7*10000中情况。 
当高位是7时,与前面的情况不同的是,75XXXX是不会越界的,后四位可以从0000取到9999,所以可以组合出10000中情况。 
两者结合就是:7*10000+10000

设我们讨论的当前位的值为A,我们统计的数字为B,我们前面讨论的三种情况,其实分别是:A小于B时,A等于B时,A大于B时。

AC代码

#include <iostream>
 
using namespace std;
 
int getNum(int n, int x)
{
    int ret = 0;
    int cur = n, high, low, temp;
    for (int base = 1; cur;base*=10,cur/=10)  //位数
    {
        temp = cur % 10;  //依次去n的每一位和x比较
        high = n / (base*10);
        low = n%base;
        if (x==0) //对0特殊处理
        {
            if (high)
            {
                high--;
            }else
                break;
        }
        ret += base*high;  //当这一位比要找的数字小时
        if (temp>x)  // 当这一位比要找的数字大时
        {
            ret += base;
        }
        else if (temp == x) //当这一位等于要找的数字时
        {
            ret += low + 1;
        }
    }
    return ret;
}
 
 
int main()
{
    int N;
    while (cin>>N)
    {
        for (int i = 0; i < 10;i++)
        {
            if (i==0)
            {
                cout << getNum(N, i);
            }
            else
            {
                cout << ' ' << getNum(N, i);
            }
        }
    }
    return 0;
}
添加笔记


01翻转

牛牛正在挑战一款名为01翻转的游戏。游戏初始有A个0,B个1,牛牛的目标就是把所有的值都变为1,每次操作牛牛可以任意选择恰好K个数字,并将这K个数字的值进行翻转(0变为1,1变为0)。牛牛如果使用最少的操作次数完成这个游戏就可以获得奖品,牛牛想知道最少的操作次数是多少?

例如:A = 4 B = 0 K = 3 
0000 -> 1110 -> 1001 -> 0100 -> 1111 
需要的最少操作次数为4 

输入描述:

输入为一行:
一共三个整数A(0 ≤ A ≤ 100,000),B(0 ≤ B ≤ 100,000),K(1 ≤ K ≤100,000).以空格分隔


输出描述:

输出一个整数,表示最少需要的操作次数。如果不能完成,则输出-1

输入例子:

4 0 3

输出例子:

4

思路分析

  • 我们的主题思路采用BFS,因为题目中对于进行反转的数字可以随意选择,且最终的目的是将所有的数字都反转为1,因此我们只需要记录0的个数即可,当0的个数为0时即达到

  • 不会做存,参考

AC代码

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int a, b, k;
bool vis[200005];
struct node {
	int a_num, b_num, step;
	node() {
		step = 0;
	}
};
queue<node> q;
int main() {
	while (cin >> a >> b >> k) {
		if (a == 0) {
			cout << 0 << endl;
			continue;
		}
		else if (a + b < k) {
			cout << -1 << endl;
			continue;
		}
		else if (a == k) {
			cout << 1 << endl;
			continue;
		}
		while (!q.empty()) q.pop();
		node cur, tem;
		cur.a_num = a; cur.b_num = b;
		memset(vis, false, sizeof(vis));
		q.push(cur);
		vis[cur.a_num] = true;
		bool key = false;
		while (!q.empty()) {
			cur = q.front(); q.pop();
			if (cur.a_num == 0) {
				cout << cur.step << endl;
				key = true;
				break;
			}
			for (int i = k; i > 0; i--) {
				tem = cur;
				if (tem.a_num >= i && tem.b_num >= (k - i)) {
					tem.a_num += k - i - i;
					tem.b_num += i - (k - i);
					tem.step++;
					if (vis[tem.a_num] == false) {
						vis[tem.a_num] = true;
						q.push(tem);
					}
				}
			}
		}
		if (key == false)
			cout << -1 << endl;
	}
	return 0;
}

Reference

原文地址:https://www.cnblogs.com/ranjiewen/p/6914261.html