牛客编程巅峰赛S2赛级

牛客编程巅峰赛S2赛级

牛客编程巅峰赛 S2赛级第11场

A题 牛牛做水题

题目描述:

牛牛喜欢做题。但他不喜欢做难题,喜欢做水题。

对于一个题号为i的题而言,题目的难度为i的所有因子之和除以i。牛牛认为难度小于2的题目都是水题。

例如:

编号为25的题目,其难度为(1+5+25)/25=1.24<2,因此这道题是水题。

编号为28的题目,其难度为(1+2+4+7+14+28)/28=2,因此这道题不是水题。

编号为30的题目,其难度为(1+2+3+5+6+10+15+30)/30=2.4>2,因此这道题也不是水题。

牛牛拿到了一个共有n道题目的题单,上面的题号为1、2、3、…、n。牛牛把上面所有的水题刷了个遍。每做一道编号为i的水题,牛牛可以获得i的快乐指数。

牛牛想知道,自己一共能获得多少快乐指数?

明显是一道水题,两个循环,第一个循环是从1到n遍历一遍,嵌套着第二个循环找到所有的因子,并求和,然后与2 * n比较,计算快乐指数。

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n;
    int ans = 0, sum = 0;
    cin>>n;
    for(int i = 1; i <= n; i++)
    {
        sum = 0;
        for(int j = 1; j <= i; j++)
        {
            if(i % j == 0) sum++;
        }
        if(sum < 2 * i) ans+=i;
    }
    cout<<ans;
}

B题 牛牛浇水

题目描述:

牛牛现在在花园养了n棵树,按顺序从第1棵到第n棵排列着。牛牛每天会按照心情给其中某一个区间的树浇水。例如如果某一天浇水的区间为[2,4],就是牛牛在这一天会给第2棵,第3棵和第4棵树浇水。树被浇水后就会成长,为了简化问题,我们假设在初始时所有树的高度为0cm。每过去一天树会自然成长1cm,每次树被浇水后当天会额外成长1cm。m天中牛牛每天都都会选一个区间[l,r]对这个区间内的树进行浇水,牛牛想知道m天后有多少棵树的高度为奇数,你能告诉牛牛吗?

这个题时间是三秒,可以暴力过,但是还可以用到一个算法,叫差分前缀和……

先看一下暴力的方法:

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int tr[10005];
    int n, m, a, b;
    int ans = 0;
    cin>>n>>m;
    for(int i = 0; i < m; i++)
    {
        cin>>a>>b;
        for(int j = a; j <= b; j++)
            tr[j]++;
    }
    for(int i = 1; i <= n; i++)
    {
        if((tr[i] + m) % 2 == 1)
            ans++;
    }
    cout<<ans;
}

用了2007毫秒的时间,属实很慢,一般比赛都会直接TL

我们来看一下差分前缀和怎么实现

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 返回m天后高度为奇数的树的数量
     * @param n int整型 
     * @param m int整型 
     * @param l int整型vector 
     * @param r int整型vector 
     * @return int整型
     */
    int oddnumber(int n, int m, vector<int>& l, vector<int>& r) {
        // write code here
        int  sum[200020] = {0};
        int ans = 0;
        for(int i = 0; i < m; i++)
        {
            sum[l[i]]++;
            sum[r[i] + 1]--;
        }
        for(int i = 1; i <= n; i++)
        {
            sum[i] += sum[i - 1];
        }
        for(int i = 1; i <= n; i++)
        {
            if((sum[i] + m) % 2 == 1)
                ans++;
        }
        return ans;
    }
};

查分前缀和见我的博客此处不详讲

C题 挑选方案问题

自助餐厅里有5个盘子,里面装的都是面包。

第1个盘子里有无限个面包;

第2个盘子里只有1个面包;

第3个盘子里只有4个面包;

第4个盘子里也有无限个面包,但必须两个两个地拿;

第5个盘子里也有无限个面包,但必须5个5个地拿;

给定正整数n,求有多少种正好拿出n个面包的方案。

方案a和方案b不同,当且仅当方案a存在从某个盘子里拿出面包的数量与方案b中对应盘子拿出的数量不同。

这个题大眼一看需要五个for循环,但是这样必然超时!

那我们从问题入手,转换成数学语言是x + y + z + 2 * a + 5 * b = n(y<= 1 , z <= 4)

在利用加法交换律和结合律,x + (y + a * 2) + (z + b * 5) = n,这样的话就可以看做是三个整数相加的和为n,求有几种方法,这就是高二数学讲排列组合时候的插空法的变性,分三种情况,第一种就是这三个数有两个都是0,就是不存在的时候,这个是 C(3,1) = 3 ;第二种情况是有两个数来分这个n,一个数不存在,就是C(3,2) * (n - 1),这个n - 1就是插空法的挡板,第三种情况是三个数都用来构成这个n,所以就是直接的插空法C(n-1,2),三种情况想加,得到最终表达式(n + 1)* (n +2) / 2.

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param n int整型 
     * @return long长整型
     */
    long long wwork(int n) {
        // write code here
        return 1ll * (n + 1) * (n + 2) / 2;
    }
};

千万别忘了乘以1ll,不然会wa.

牛客编程巅峰赛 S2赛级第10场

A题 数学实验

牛牛在做数学实验。

老师给了牛牛一个数字n,牛牛需要不断地将所有数位上的值做乘法运算,直至最后数字不发生变化为止。

请你帮牛牛计算一下,最后生成的数字为多少?

思路:当n小于10的时候,最后的数字就不会改变了,所以n<10就是循环截止的条件,然后我们只需要在循环内嵌套一个循环,用来将每一位的数相乘即可

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param n long长整型 老师给牛牛的数字
     * @return int整型
     */
    int mathexp(long long n) {
        int ans;
        while(n >= 10)
        {
            ans = 1;
            while(n)
            {
                ans *= n % 10;
                n /= 10;
            }
            n = ans;;
        }
        return n;//一定要记得返回n不是返回ans,因为如果输入的是小于0的数,返回n才是对的
    }
};

B题 奇怪的排序问题

操场上有n个人排成一队,这n个人身高互不相同,可将他们的身高视为一个1到n的排列。

这时需要把队伍变成升序,也就是从矮到高排序。

每次可以选择一个人,让这个人和在他身后的人比高矮,如果比对方高,则交换位置并继续下一次比较,直到比对方矮或者已经在队尾。

现在给出数n和一个1到n的排列,求最少的选择次数,使队伍变为升序。

这是个思维题,从队列尾部开始往前判断,因为是要找变为升序的最少次数,就是判断一下,tr[i] 与 minx比较,minx 初始是最大值(本题是n + 1),如果前者大,则将前者的值赋给minx,不计数,再继续循环;如果后者大,说明tr[i]得交换,所以加一,minx不变。

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param n int整型 
     * @param a int整型vector 
     * @return int整型
     */
    int wwork(int n, vector<int>& a) {
        int ans = 0;
        int minx = n + 1;
        for(int i = n - 1; i >= 0; i--)
        {
            if(a[i] > minx) ans++;
            else minx = a[i];
        }
        return ans;
    }
};

C题 XOR和

牛牛最近学会了异或操作,于是他发现了一个函数f(x)=x⊕(x−1)f(x)=x\oplus (x-1)f(x)=x⊕(x−1),现在牛牛给你一个数n\mathit nn,他想知道∑i=1nf(i)\sum_{i=1}^n f(i)∑i=1nf(i)的值是多少,请你告诉他。

直接莽暴力

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param n int整型 
     * @return long长整型
     */
    long long Sum(int n) {
        long long sum = 0;
        for(int i = 1; i <= n; i++)
        {
            sum += i ^(i - 1);
        }
        return sum;
    }
};

看了别人的代码,有神奇的操作,但是我不懂(手动狗头

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param n int整型 
     * @return long长整型
     */
    long long  dfs(long long t) {
	if(t==1) return 1;
	if(t==0) return 0;
	return 	t+2*dfs(t/2);
}
    long long Sum(int n) {
        // write code here
        long long ans = n;
        ans+=2*dfs(n/2);
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_51216553/article/details/111668522