牛客编程巅峰赛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);
    }
};

容斥原理