vivo2020屆春季校園招聘在線編程考試 解題報告
題目鏈接:牛客鏈接
A. 手機屏幕解鎖模式
分析:
這是一個智能手機的圖案鎖,有3*3=9個點。現在要求所有圖案中經過的點的個數再[m,n]這個範圍內的方案數。一個點也算作一種方案(和一般圖案鎖不太一樣)。
我們可以大致計算一下總共方案的個數,大概是9!這麼多。當然,我們只是算了個大概,沒有考慮圖案的限制。這個大小遠遠小於10^8, 我們可以直接dfs所有方案。我們從9個點都出發一遍,每次在1-9之中都判斷一次,如果還沒走過,就可以考慮走到這個點。 我們一路dfs下去,如果遇到一個方案它的路徑長度(經過點的個數)在[m,n]範圍之內,我們就計數。如果路徑長度大於n, 我們就不必往下繼續搜索了。
我們需要注意一個問題,就是如果路徑之中的前後兩個點A, C中間那個點B還沒有走過,我們就不能跨過這個點,不然A->B->C會被重複計數,因爲dfs(A)的時候已經去過B了。
這題要求寫在測試類裏面,int solution(int m,int n)
代碼:
#include <bits/stdc++.h>
using namespace std;
void dfs(int m,int n,int x,int now,int &cnt,bool * vis,int * r) {
if(x>n) return;
r[x] = now;
if(x>=m) {
++cnt;
// for(int i=1;i<=x;++i) cout<<r[i]<<" ";cout<<endl;
}
vis[now] = true;
for(int to=0;to<9;++to) {
if(vis[to]) continue;
int px = now/3, py = now%3;
int xx = to/3, yy = to%3;
if(abs(px-xx)%2==0&&abs(py-yy)%2==0) {
int mdx = (px+xx)/2, mdy = (py+yy)/2;
int mid = mdx*3+mdy;
if(vis[mid])
dfs(m,n,x+1,to,cnt,vis,r);
}
else
dfs(m,n,x+1,to,cnt,vis,r);
}
vis[now] = false;
}
int solution(int m,int n) {
int cnt = 0;
bool * vis = new bool[10];
int * r = new int[10];
for(int i=0;i<10;++i) vis[i] = false,r[i]=-1;
for(int i=0;i<9;++i)
dfs(m,n,1,i,cnt,vis,r);
delete []vis;
delete []r;
return cnt;
}
int main(void) {
int m,n;
while(cin>>m>>n) {
cout<<solution(m,n)<<endl;
}
return 0;
}
直接把dfs()和solution(int m,int n)兩個函數複製到class Solution()作爲成員函數即可。
B. 數位之積
分析:
測試類要求的函數輸入的參數n和輸出的答案都是int。
我們可以分析一下, 要求y的各個數位乘積等於n。我們把n分解質因數,得到n = P1^C1 * P2^C2 * P3^C3 * ... * Pk^Ck
。 因爲十進制整數每個數位最大爲9,所以如果n存在大於9的質因數,我們便無法實現。所以,n只能包含2
,3
,5
,7
這4個質因數。
如果n==0,則y最小爲10,如果1<=n<=9, 那麼y最小爲n+10,因爲題目要求y>9。
處理完特殊的小數字後我們就可以開始討論一般的輸入。
- 如果n的質因數存在大於7的,那麼n不可以被y的數位乘積表示,輸出-1
- n最多隻含有上述的4個質因數,那麼我們就可以把n表示爲:
n = 2^C2 * 3^C3 * 5^C5 * 7^C7
。(C2,C3,C5,C7>=0) - 我們貪心地考慮,要使得y最小,首先要使y有最少的數位,其次在最少數位的基礎上,我們要使得y的字典序最小。
- 首先,
5
和7
必須一個佔一位,不然會超過9。我們先把2^3替換爲8,3^2替換爲9,這樣能有效減少數位。然後3可能剩下0或1個,2可能剩下0,1,2個。如果只剩下2,優先把2^2都替換爲4。如果有1個3,1個2,就替換爲6。如果有2個2一個3,就替換爲2,6。 - 我們處理出2,3,4,5,6,7,8,9的個數後,就可以貪心地小數在前大數在後得到答案了。
代碼:
#include <bits/stdc++.h>
using namespace std;
int solution(int n) {
if(n==0) return 10;
if(n<=9) return 10+n;
int c2 = 0, c3 = 0, c5 = 0, c7 = 0;
while(n%2==0) c2++, n/=2;
while(n%3==0) c3++, n/=3;
while(n%5==0) c5++, n/=5;
while(n%7==0) c7++, n/=7;
if(n>1) return -1;
int c8 = 0, c9=0,c4=0,c6=0;
c8 = c2/3; c2 %= 3;
c9 = c3/2; c3 %= 2;
if(c3==0) {
c4 = c2/2; c2%=2;
} else { //c3==1
if(c2==1) c2=0,c3=0,c6=1;
else if(c2==2) c2=1,c3=0,c6=1;
}
int ans = 0;
while(c2--) ans = ans*10+2;
while(c3--) ans = ans*10+3;
while(c4--) ans = ans*10+4;
while(c5--) ans = ans*10+5;
while(c6--) ans = ans*10+6;
while(c7--) ans = ans*10+7;
while(c8--) ans = ans*10+8;
while(c9--) ans = ans*10+9;
if(ans<0) return -1;
return ans;
}
int main(void) {
int x;
while(cin>>x) {
cout<<solution(x)<<"\n";
}
return 0;
}
C. vivo智能手機產能
時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 256M,其他語言512M
在vivo產線上,每位職工隨着對手機加工流程認識的熟悉和經驗的增加,日產量也會不斷攀升。
假設第一天量產1臺,接下來2天(即第二、三天)每天量產2件,接下來3天(即第四、五、六天)每天量產3件 … …
以此類推,請編程計算出第n天總共可以量產的手機數量。
分析:
1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 7 7…
二分找出最後一個連續的數字,然後求和即可。
1^2 + 2^2 + 3^2 + ...+n^2 = n*(n+1)*(2n+1)/6
代碼:
#include <bits/stdc++.h>
using namespace std;
int solve(int n) {
int left=0,right = 1000000;
if(n<=1) return n;
while(right-left>1) {
int mid = (left+right)>>1;
if(1ll*mid*(1+mid)/2>n) right = mid;
else left = mid; //[)
}
int ans = 1ll*left*(left+1)*(2*left+1)/6;
n -= (1+left)*left/2;
ans += n*(left+1);
return ans;
}
int main(void) {
int x;
while(cin>>x)
{
cout<<solve(x)<<"\n";
}
return 0;
}
2020/4/10 12:33
xzc