牛客巅峰赛S2第三场题解(青铜白银组)
更多内容欢迎关注我的公众号ACJavaBear,一起学习Java。
1.牛牛打怪
题目描述
牛牛在各个平台被各种传奇游戏的广告轰炸,所以他决定去玩一玩这类的游戏。这类游戏挂机就可以升级,所以牛牛每天都能变强。在第i天里,牛牛能杀死防御力小于等于i的怪物。但由于牛牛还要刷题,所以牛牛每天最多杀一只怪物。这个游戏共有n只怪物,每只怪物的防御力为DEF[i],牛牛想知道最少要到第几天才能把这n只怪物都杀死。
样例1
输入
2,[7,3]
返回
7
说明
牛牛可以在第3天杀死一只防御力为3的怪物,在第7天杀死一只防御力为7的怪物。所以牛牛最少能在第7天把这些怪物全杀死。
样例2
输入
3,[4,5,5]
返回
6
说明
牛牛可以在第4天杀死一只防御力为4的怪物,在第5天杀死一只防御力为5的怪物,在第六天将另一只防御力为5的怪杀死。所以牛牛最少能在第6天把这些怪物全杀死。
备注
1 ≤ n ≤ 1 0 3 , 1 ≤ D E F [ i ] ≤ 1 0 6 1≤n≤10^3, 1≤DEF[i]≤10^6 1≤n≤103,1≤DEF[i]≤106
题解
仔细读题可以发现,其实就是一个比较简单的动态规划问题。
我们可以先把数组按升序排序,设一数组dp
,dp[i]
表示 把第
i
i
i 只怪兽打死需要到第几天。
而无非就两种情况,要么第
i
i
i 只怪兽的防御力大,所以应该到 DEF[i]
天才能打败它,要么就是我们现在就能打败第
i
i
i 只怪兽,但仍然需要花一天的时间,所以就是 dp[i-1] + 1
天。dp
一维数组可以优化成一个变量存储 。
public class Solution {
public int Minimumdays (int n, int[] DEF) {
// write code here
Arrays.sort(DEF);
int cnt = DEF[0];
for(int i = 1; i < n; i++){
cnt = Math.max(DEF[i],cnt+1);
}
return cnt;
}
}
2.简单的公式
题目描述
现在有3个数组a,b,c
a[1]=2,a[2]=6,对所有的n>=3,a[n] = 2a[n-1] + 3a[n-2]。
b[1]=7,b[2]=35,对所有的n>=3,b[n] = 3b[n-1] + 10b[n-2]。
对所有的n>=1,有c[n] = a[n]*b[n]。
现在给你一个正整数n,返回c[n]%1000000007的值。
样例1
输入
2
返回
210
说明
a[2]=6,b[2]=35,c[2]=a[2]*b[2]=210。
样例2
输入
10
返回
207027484
备注
对于百分之20的数据: 1 ≤ n ≤ 1 0 3 1≤n≤10^3 1≤n≤103
对于百分之50的数据: 1 ≤ n ≤ 1 0 7 1≤n≤10^7 1≤n≤107
对于百分之100的数据: 1 ≤ n ≤ 1 0 18 1≤n≤10^{18} 1≤n≤1018
请注意本题的空间限制为32MB
题解
根据两个递推公式,我们可以推出, a { n } a\{n\} a{n} 与 b { n } b\{n\} b{n} 为两个等比数列。
可以得出 a [ n ] = a 1 ∗ q n − 1 a[n] = a_1*q^{n-1} a[n]=a1∗qn−1,即 a [ n ] = 2 ∗ 3 n − 1 a[n] = 2 * 3 ^{n-1} a[n]=2∗3n−1
同理可得 b [ n ] = 7 ∗ 5 n − 1 b[n] = 7 * 5 ^{n-1} b[n]=7∗5n−1
故 c [ n ] = 14 ∗ 1 5 n − 1 c[n] = 14 * 15 ^{n-1} c[n]=14∗15n−1。
到此由于数据范围最大可到 1 0 18 10^{18} 1018 ,所以我们需要用快速幂来求解。
import java.util.*;
public class Solution {
long p = 1000000007;
public int Answerforcn (long n) {
// write code here
return (int) (14 * qmi( 15,n-1) % p);
}
//快速幂模板
public long qmi(long a,long b){
long res = 1;
while(b != 0){
if((b & 1) == 1) res = res * a % p;
b >>= 1;
a = a * a % p;
}
return res;
}
}
3.Tree VI
题目描述
系统中有一棵n个点的完全k叉树,现给出它的DFS先序遍历序列 a i a_i ai,请你还原这棵树,并返回加密后的答案。 答案加密方法:所有边两个端点异或的和。
下面给出完全二叉树的定义:若设二叉树的深度为k,除第 k 层外,其它各层 (1~k-1) 的结点数都达到最大个数,第k层所有的结点都连续集中在最左边。 请你根据这个定义进行适度推广,得到完全k叉树的含义。
样例1
输入
2,[1,2,3,4,5]
返回
14
说明
树边为(1, 2), (1, 5), (2, 3), (2, 4),加密过程为(1^2)+(1^5)+(2^3)+(2^4),答案为14。
样例2
输入
3,[1,2,3,4,5]
返回
13
说明
树边为(1, 2), (1, 4), (1, 5), (2, 3),加密过程为(1^2)+(1^4)+(1^5)+(2^3),答案为13
备注
数据满足: 1 ≤ n , k ≤ 1 0 5 , 1 ≤ a i ≤ 1 0 9 1≤n,k≤10^5, 1≤ai≤10^9 1≤n,k≤105,1≤ai≤109
题解
由于数组给出的是 D F S DFS DFS 序,而之前我们做了一道 B F S BFS BFS 序的同类型题目。我们可以借助 B F S BFS BFS 序帮助遍历。具体见代码。
public class Solution {
int kk = 0;
int bfsOrder = 0; // 记录bfs序
int dfsOrder = 0; // 记录dfs序,即为数组下标
long res = 0;
public long tree6 (int k, int[] a) {
kk = k;
dfs(a,bfsOrder);
return res;
}
public void dfs(int[] a,int bfsOrder){
if(dfsOrder >= a.length) return ;
int p = a[dfsOrder]; //记录当前结点值
for(int i = 1; i <= kk; i++){
if(bfsOrder * kk + i < a.length){ //判断当前结点有没有儿子
dfsOrder++; //有儿子则到儿子一层
res += (p ^ a[dfsOrder]); //计算结果
dfs(a,bfsOrder * kk + i); //进入下一层
}
}
}
}