layout: post
title: 牛客網2017年校招全國統一模擬筆試(第三場)編程題集合
date: 2017-06-10
tag: oj
- 上次做的題只叫一個字慘!剛好抽到了做最后三題,沒有一道全部AC掉!
- 這種題主要是讀懂題意,然后抽象成簡單的,遇到過得問題。
- 需要多總結,不然下次還這樣!
變換次數
牛牛想對一個數做若干次變換,直到這個數只剩下一位數字。
變換的規則是:將這個數變成 所有位數上的數字的乘積。比如285經過一次變換后轉化成2*8*5=80.
問題是,要做多少次變換,使得這個數變成個位數。
輸入描述:
輸入一個整數。小於等於2,000,000,000。
輸出描述:
輸出一個整數,表示變換次數。
輸入例子:
285
輸出例子:
2
- 自己寫的代碼,找了很多細節錯誤,才全部AC掉,對特殊情況的處理不好!
#include<iostream>
using namespace std;
int getbitmul(int N)
{
int retmul=1;
if(N>-10&&N<10)
return N;
while(N)
{
int temp=N%10;
N/=10;
retmul*=temp;
}
return retmul;
}
int main()
{
int N;
int cnt=0;
cin>>N;
if(N>-10&&N<10)
{
cout<<cnt<<endl;
return 0;
}else
{
int ret = getbitmul(N);
cnt=1;
while(ret/10!=0)
{
ret=getbitmul(ret);
cnt++;
}
}
cout<<cnt<<endl;
return 0;
}
- 下面參考的就清楚多了
#include<iostream>
using namespace std;
int main()
{
int num, count, tmp;
count = 0;
cin >> num;
while (num > 9)
{
tmp = 1;
for (; num; num = num / 10)
{
tmp = tmp*(num % 10);
}
num = tmp;
count++;
}
cout << count << endl;
return 0;
}
神奇數
- 題目
給出一個區間[a, b],計算區間內“神奇數”的個數。
神奇數的定義:存在不同位置的兩個數位,組成一個兩位數(且不含前導0),且這個兩位數為質數。
比如:153,可以使用數字3和數字1組成13,13是質數,滿足神奇數。同樣153可以找到31和53也為質數,只要找到一個質數即滿足神奇數。
輸入描述:
輸入為兩個整數a和b,代表[a, b]區間 (1 ≤ a ≤ b ≤ 10000)。
輸出描述:
輸出為一個整數,表示區間內滿足條件的整數個數
輸入例子:
11 20
輸出例子:
6
- AC代碼
- 枚舉區間的數字,得到每一位,然后判斷組合的數字是否為質數。
#include<iostream>
#include<math.h>
using namespace std;
bool IsPrime(int data)
{
int i = 0;
if (data==2)
{
return true;
}
for (int k = 2;k<=sqrt(data);k++)
{
if (data%k==0)
{
return false;
}
}
return true;
}
bool IsMagicNum(int num)
{
int a[5] = { 0 };
int i = 0; //i為位數
while (num)
{
a[i++] = num % 10;
num /= 10;
}
int data = 0;
for (int k = 0; k < i;k++) //用i來限定位數,減少搜索
{
for (int j = 0; j < i;j++)
{
if (k!=j &&a[k]!=0 && a[j]!=0) //排除0的位數
{
data = a[k] * 10 + a[j];
if (IsPrime(data))
{
return true;
}
}
}
}
return false;
}
int main()
{
int a, b;
cin >> a >> b;
int ret = 0;
for (int i = a; i <= b;i++)
{
if (IsMagicNum(i))
{
ret++;
}
}
cout << ret << endl;
return 0;
}
}
添加字符
- 題目
牛牛手里有一個字符串A,羊羊的手里有一個字符串B,B的長度大於等於A,所以牛牛想把A串變得和B串一樣長,這樣羊羊就願意和牛牛一起玩了。
而且A的長度增加到和B串一樣長的時候,對應的每一位相等的越多,羊羊就越喜歡。比如"abc"和"abd"對應相等的位數為2,為前兩位。
牛牛可以在A的開頭或者結尾添加任意字符,使得長度和B一樣。現在問牛牛對A串添加完字符之后,不相等的位數最少有多少位?
輸入描述:
第一行為字符串A,第二行為字符串B,A的場地小於等於B的長度,B的長度小於等於50.字符均為小寫字母。
輸出描述:
輸出一個整數表示A串添加完字符之后,不相等的位數最少有多少位?
輸入例子:
abe
cabc
輸出例子:
1
-
分析:情況分為兩種:1.A的長度小於B的長度;2.A的長度等於B的長度當小於時,就枚舉B串的一個偏移量,然后枚舉維護最小的不相等的位數。當等於時,就直接對比就好了。
-
AC代碼
#include<iostream>
#include <string>
using namespace std;
//想本來想是兩個字符串的最小公共子串問題,但是感覺不適用,eg:abc-aec
int main()
{
string a, b;
cin >> a >> b;
int cnt = 0;
int ret = 1e9;
if (a.length()==b.length()) //b>a
{
for (int i = 0; i < a.length();i++)
{
if (a[i]!=b[i])
{
cnt++;
}
}
if (cnt<ret)
{
ret = cnt;
}
}
else if (a.length()<b.length())
{
for (int i = 0; i < b.length() - a.length()+1;i++)
{
for (int j = 0; j < a.length();j++)
{
if (a[j]!=b[i+j])
{
cnt++;
}
}
if (cnt<ret)
{
ret = cnt;
}
cnt = 0;
}
}
else
{
cout << "a字符串長度大於b的長度!";
}
cout << ret << endl;
return 0;
}
數組變換
- 題目
牛牛有一個數組,里面的數可能不相等,現在他想把數組變為:所有的數都相等。問是否可行。
牛牛可以進行的操作是:將數組中的任意一個數改為這個數的兩倍。
這個操作的使用次數不限,也可以不使用,並且可以對同一個位置使用多次。
輸入描述:
輸入一個正整數N (N <= 50)
接下來一行輸入N個正整數,每個數均小於等於1e9.
輸出描述:
假如經過若干次操作可以使得N個數都相等,那么輸出"YES", 否則輸出"NO"
輸入例子:
2
1 2
輸出例子:
YES
- 我是直接排序算的
- 參考分析:把數組每一個元素都除以2,直到它為奇數。如果此時數組每個元素都一樣,滿足條件,輸出YES
- AC代碼
#include <iostream>
#include<vector>
#include <algorithm>
using namespace std;
int main()
{
int N;
cin >> N;
vector<int> vec;
int num;
for (int i = 0; i < N;i++)
{
cin >> num; //正整數沒有0
vec.push_back(num); //也可以在push_back標記最大值,就不需要排序了
}
sort(vec.begin(),vec.end());
bool flag = true;
for (int i = 0; i < vec.size()-1;i++)
{
if (vec[vec.size()-1]%vec[i]!=0 /*&& vec[1]!=0*/)
{
flag = false;
break;
}
}
if (flag)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
return 0;
}
排序子序列
- 題目
牛牛定義排序子序列為一個數組中一段連續的子序列,並且這段子序列是非遞增或者非遞減排序的。牛牛有一個長度為n的整數數組A,他現在有一個任務是把數組A分為若干段排序子序列,牛牛想知道他最少可以把這個數組分為幾段排序子序列.
如樣例所示,牛牛可以把數組A划分為[1,2,3]和[2,2,1]兩個排序子序列,至少需要划分為2個排序子序列,所以輸出2
輸入描述:
輸入的第一行為一個正整數n(1 ≤ n ≤ 10^5)
第二行包括n個整數A_i(1 ≤ A_i ≤ 10^9),表示數組A的每個數字。
輸出描述:
輸出一個整數表示牛牛可以將A最少划分為多少段排序子序列
輸入例子:
6
1 2 3 2 2 1
輸出例子:
2
- 參考考慮序列
A_1, A_2, . . . , A_i
是一個單調的序列.顯然如果對於j < i
把序列分為A_1, A_2. . . A_j
和A_j+1, A_j+2, . . . , A_i
兩個部分不會使問題變得更優.於是我們可以貪心的去重復下面過程: 1、 從序列中找出最長的單調連續子序列 2、 刪除找出的最長的單調連續子序列這里的單調序列包括非遞增和非遞減,而判斷子序列是否單調的時候,注意處理等於的情況。 - 貪心達到最優
- AC代碼
#include<iostream>
#include <vector>
using namespace std;
int main()
{
int N;
cin >> N;
vector<int> vec;
int num;
int ret = 0;
for (int i = 0; i < N;i++)
{
cin >> num;
if (vec.size()<=1)
{
vec.push_back(num);
}
else //進行在線更新判斷
{
if (vec[0]<=vec.back()&&vec.back()<=num ) //單調增
{
vec.push_back(num);
}else if (vec[0]>=vec.back() && vec.back()>=num) //單調減
{
vec.push_back(num);
}
else //出現非單調時候,刪除已經存在的單調序列
{
ret++;
vec.clear();
vec.push_back(num);
}
}
}
cout << ret+1 << endl; //最后一個序列
return 0;
}
組隊競賽
- 題目
牛牛舉辦了一次編程比賽,參加比賽的有3*n個選手,每個選手都有一個水平值a_i.現在要將這些選手進行組隊,一共組成n個隊伍,即每個隊伍3人.牛牛發現隊伍的水平值等於該隊伍隊員中第二高水平值。
例如:
一個隊伍三個隊員的水平值分別是3,3,3.那么隊伍的水平值是3
一個隊伍三個隊員的水平值分別是3,2,3.那么隊伍的水平值是3
一個隊伍三個隊員的水平值分別是1,5,2.那么隊伍的水平值是2
為了讓比賽更有看點,牛牛想安排隊伍使所有隊伍的水平值總和最大。
如樣例所示:
如果牛牛把6個隊員划分到兩個隊伍
如果方案為:
team1:{1,2,5}, team2:{5,5,8}, 這時候水平值總和為7.
而如果方案為:
team1:{2,5,8}, team2:{1,5,5}, 這時候水平值總和為10.
沒有比總和為10更大的方案,所以輸出10.
輸入描述:
輸入的第一行為一個正整數n(1 ≤ n ≤ 10^5)
第二行包括3*n個整數a_i(1 ≤ a_i ≤ 10^9),表示每個參賽選手的水平值.
輸出描述:
輸出一個整數表示所有隊伍的水平值總和最大值.
輸入例子:
2
5 2 8 5 1 5
輸出例子:
10
- 分析:對於所有參賽隊員,我們把他們的水平值進行逆序排序,然后逐一挨着安排每個隊伍,然后計算出隊伍水平值總和,即為所求。
- AC代碼
#include<iostream>
#include <vector>
#include<algorithm>
using namespace std;
int main()
{
int N;
cin >> N;
int ai ;
vector<int> vec;
for (int i = 0; i < 3 * N;i++)
{
cin >> ai;
vec.push_back(ai);
}
sort(vec.begin(), vec.end());
long long ans = 0; //注意輸出溢出
//自己思路:排序后安排中間的N個元素就行了,並不是最大的,AC不過
//需要的是:從N個元素開始,相鄰兩個開始分配
for (int i = 0; i < N;i++)
{
ans += vec[2*i+N];
}
cout << ans << endl;
return 0;
}
牛牛的數列
- 題目
牛牛現在有一個n個數組成的數列,牛牛現在想取一個連續的子序列,並且這個子序列還必須得滿足:最多只改變一個數,就可以使得這個連續的子序列是一個嚴格上升的子序列,牛牛想知道這個連續子序列最長的長度是多少。
輸入描述:
輸入包括兩行,第一行包括一個整數n(1 ≤ n ≤ 10^5),即數列的長度;
第二行n個整數a_i, 表示數列中的每個數(1 ≤ a_i ≤ 10^9),以空格分割。
輸出描述:
輸出一個整數,表示最長的長度。
輸入例子:
6
7 2 3 1 5 6
輸出例子:
5
- 分析:正着枚舉記錄一下當前位置的連續上升子序列長度,倒着也做一遍。最后枚舉一個連接點即可。
- AC代碼
#include <cstdio>
#include <cstdlib>
const int maxn = 100000 + 5;
const int maxdata = 1e9 + 1;
#define max(a,b) (((a) > (b)) ? (a) : (b))
int a[maxn], n;
int pre[maxn], post[maxn];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n;i++)
{
scanf("%d", &a[i]);
}
a[0] = maxdata, a[n + 1] = maxdata;
for (int i = 1; i <= n;i++)
{
pre[i] = a[i - 1] < a[i] ? pre[i - 1] + 1 : 1;
}
for (int i = n; i>0;i--)
{
post[i] = a[i] < a[i + 1] ? post[i+1] + 1 : 1;
}
int ans = 1;
for (int i = 1; i <= n;i++)
{
//ans = max(ans, pre[i - 1] + 1);
//ans = max(ans, post[i + 1] + 1);
if (a[i + 1] - a[i - 1] >= 2)
ans = max(ans, pre[i - 1] + post[i + 1] + 1);
}
printf("%d\n", ans);
return 0;
}
訓練部隊
小牛牛是牛牛王國的將軍,為了訓練出精銳的部隊,他會對新兵進行訓練。部隊進入了n個新兵,每個新兵有一個戰斗力值和潛力值,當兩個新兵進行決斗時,總是戰斗力值高的獲勝。獲勝的新兵的戰斗力值就會變成對手的潛力值 + 自己的戰斗力值 - 對手的戰斗力值。敗者將會被淘汰。若兩者戰斗力值一樣,則會同歸於盡,雙雙被淘汰(除了考察的那個新兵之外,其他新兵之間不會發生戰斗) 。小牛牛想知道通過互相決斗之后新兵中戰斗力值+潛力值最高的一個可能達到多少,你能幫助小牛牛將軍求出來嗎?
輸入描述:
輸入包括n+1行,第一行包括一個整數n(1 ≤ n ≤ 10^5);
接下來的n行,每行兩個整數x和y(1 ≤ x,y ≤ 10^9)
輸出描述:
輸出一個整數,表示新兵中戰斗力值+潛力值最高的一個能達到多少。
輸入例子:
2
1 2
2 1
輸出例子:
4