牛客编程巅峰赛S2第3场
-> 青铜&白银&黄金
https://ac.nowcoder.com/acm/contest/9246
钻石&王者
https://ac.nowcoder.com/acm/contest/9247
2020-11-24 20:00:00 至 2020-11-24 21:00:00
时长: 1小时
AC 2/3
Rank 195/696
罚时 01:44:59
A (555/1916) 00:20:15 (-1)
B (205/1349) 00:59:44 (-4)
C (56/187)
A 牛牛打怪
牛牛在各个平台被各种传奇游戏的广告轰炸,所以他决定去玩一玩这类的游戏。这类游戏挂机就可以升级,所以牛牛每天都能变强。在第i天里,牛牛能杀死防御力小于等于i的怪物。但由于牛牛还要刷题,所以牛牛每天最多杀一只怪物。这个游戏共有n只怪物,每只怪物的防御力为DEF[i],牛牛想知道最少要到第几天才能把这n只怪物都杀死。
A.1 比赛时AC
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * @param n int整型 * @param DEF int整型vector * @return int整型 */ int Minimumdays(int n, vector<int>& DEF) { // write code here sort(DEF.begin(),DEF.end()); for(int i=1;i<n;i++){ if(DEF[i]<=DEF[i-1]){ DEF[i]=DEF[i-1]+1; } } return max(n,DEF[n-1]); } };
思路这样解释比较形象:
从小到大排列后,如果有相同数值的会形成一个平台。
而一天内最多只能打一个,
所以平台内的第二天需要增高一个台阶,
后面类似,小于等于前一个的数值将被更改为前一个的数值加一。
if(DEF[i]<=DEF[i-1]) DEF[i]=DEF[i-1]+1;
A.2 讲解
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * @param n int整型 * @param DEF int整型vector * @return int整型 */ int Minimumdays(int n, vector<int>& DEF) { // write code here sort(DEF.begin(),DEF.end()); int cnt=DEF[0],i; for(i=1;i<DEF.size();i++){ cnt=max(DEF[i],cnt+1); } return cnt; } };
B 简单的公式
现在有3个数组a,b,c
a[1]=2,a[2]=6,对所有的n>=3,。
b[1]=7,b[2]=35,对所有的n>=3,。
对所有的n>=1,有c[n] = a[n]*b[n]。
现在给你一个正整数n,返回c[n]%1000000007的值。
B.1 比赛时AC
class Solution { public: /** * 返回c[n]%1000000007的值 * @param n long长整型 即题目中的n * @return int整型 */ int Answerforcn(long long n) { // write code here long long a=15,b=n-1,c=1000000007; long long ans = 14,base=a; base = base % c; if(b==0){ return 14%c; } while(b){ if(b & 1) ans = (ans*base) % c; b = b >> 1; base = (base * base) % c; } return ans%c; } };
其实这道题算作弊了。。
一开始没想到怎么算通项公式,
直接用特征方程来解的。
解得
通项公式为
其中由初始条件
求得。
后面算出之后超时了一次。
然后莫名其妙觉得余数会循环(并不会循环)。浪费了很多时间
搜了下“幂取模”,搜到了模板 | 整数快速幂 & 快速幂取模,。
// time:O(logN) // 这里不考虑指数为负数的情况 int pow_mod(int a,int b,int c) { int ans = 1,base=a;// ans:结果;base:底数 base = base % c; //【考虑0次方的情况】 if(b==0) { return 1%c;// 任意a的0次幂都是1,故直接用1%c即可 } while(b) { if(b & 1) // 与运算,判断奇偶性 ans = (ans*base) % c; b = b >> 1;// 右移一位,相当于除2 base = (base * base) % c; } return ans; }
就直接套进来了,一开始还忘记改b=0的情况了,后来改成14,终于AC了,2020-11-24 20:59:44,还差16秒结束,终于赶上了一道。
B.2 讲解
class Solution { public: /** * 返回c[n]%1000000007的值 * @param n long长整型 即题目中的n * @return int整型 */ typedef long long ll; int mod=1e9+7; ll power(ll a,ll b){ ll res=1; while(b){ if(b%2==1)res=res*a%mod; b/=2; a=a*a%mod; } return res; } int Answerforcn(long long n) { // write code here return 14*power(15,n-1)%mod; } };
C Tree VI
系统中有一棵n个点的完全k叉树,现给出它的DFS先序遍历序列 ,请你还原这棵树,并返回加密后的答案。
答案加密方法:所有边两个端点异或的和,即 ,其中
为一条树上的边。
下面给出完全二叉树的定义:若设二叉树的深度为k,除第 k 层外,其它各层 (1~k-1) 的结点数都达到最大个数,第k层所有的结点都连续集中在最左边。
请你根据这个定义进行适度推广,得到完全k叉树的含义。
C.1 比赛时
又没做到这一题,太惨了。
C.2 讲解
class Solution { public: /** * * @param k int整型 表示完全k叉树的叉数k * @param a int整型vector 表示这棵完全k叉树的Dfs遍历序列的结点编号 * @return long长整型 */ typedef long long ll; ll kk,nn,temp=1,res=0; vector<int> aa; void dfs(int x,int cnt){ int i; for(i=1;i<=kk;i++){ if(kk*x+i<nn){ temp++; res+=aa[temp-1]^aa[cnt-1]; dfs(kk*x+i,temp); } else return; } } long long tree6(int k, vector<int>& a) { // write code here kk=k ,nn=a.size(),aa=a; dfs(0,1); return res; } };
引入BFS 辅助思考
D 整除问题
给定 ,求所有
被 2021 整除的
数对个数,其中
。
D.1 讲解
class Solution { public: /** * 寻找所有能整除 2021 的数对个数 * @param a long长整型 * @param b long长整型 * @param c long长整型 * @param d long长整型 * @return long长整型 */ long long f(long long a, long long b){ return a/2021*b+b/2021*a-a/2021*(b/2021)+(a/43-a/2021)*(b/47-b/2021)+(a/47-a/2021)*(b/43-b/2021); } long long findPairs(long long a, long long b, long long c, long long d) { // write code here return f(b,d)-f(a-1,d)-f(b,c-1)+f(a-1,c-1); } };
容斥原理