牛客 小白月赛41题解

比赛链接

A.小红的签到题

知识点:贪心
思路:签到题,由于题目保证了输入合法,所以不需要考虑b,答案为c/a。
时间复杂度:O(1)
参考代码:

#include<iostream>
using namespace std;

int main()
{
	int a,b,c;
	cin>>a>>b>>c;
	cout<<c/a;
	return 0;
}
B.小红的ABC

知识点:字符串
思路1:由于题目给的数据范围小,所以直接暴力枚举每一个子串,判断是否为回文串并记录最小长度。
时间复杂度:O(N3)
参考代码1:

#include<iostream>
#include<string>
using namespace std;

//判断是否为回文串,是返回true,不是返回false
bool hw(string &t)
{
    int n=t.size();
    //从字符串的两端同时遍历,若有不一样的字符则说明不是回文串
    for(int i=0;i<n/2;i++)
        if(t[i]!=t[n-1-i])
            return false;
    return true;
}
//返回最小回文子串的长度
int shortHw(string &s)
{
    //将答案初始化最大,方便迭代
    int res=0x3f;
    int n=s.size();
    //i表示字符串的开头,j表示子串的长度
    for(int i=0;i<n-1;i++)
        for(int j=2;j<=n-i;j++)
        {
            string t=s.substr(i,j);
            int num=t.size();
            //当子串是回文串并且长度大于1时,更新答案
            if(hw(t)&&num>1)    res=min(res,num);
        }
    if(res!=0x3f)   return res;
    //若没有符合题意的答案,则要返回-1
    return -1;
}
int main()
{
    string s;
    cin>>s;
    cout<<shortHw(s);
    return 0;
}

思路2:任何长度为n(n>3)的回文字符串,一定可以通过去掉首尾字母,生成一个长度为n-2的回文字符串,以此一直迭代下去,就只有长度为2和3的回文字符串两种可能,也即将原问题转化为判定是否存在长度为2,3的回文字符串。
长度为2的回文字符串的判定方法:判断是否存在两个相邻的相同字符
长度为3的回文字符串的判定方法:判断是否存在两个下标距离为2的相同字符
时间复杂度:O(N)
参考代码2:

#include<iostream>
using namespace std;

int main()
{
    string s;
    cin>>s;
    //判断是否有两个连续的相同字符
    for(int i=1;i<s.size();i++)
        if(s[i-1]==s[i])
        {cout<<2;return 0;}
        //return 0可以提前结束程序
    //判断是否有间隔一个的相同字符
    for(int i=1;i<s.size()-1;i++)
        if(s[i-1]==s[i+1])
        {cout<<3;return 0;}
    //没有答案的话输出-1
    cout<<-1;
    return 0;
}
C.小红的口罩

知识点:贪心,堆
思路1:每次都选用舒适度最小的口罩。先将口罩初始的不舒适度从小到大排序,然后取第一个(也就是舒适度最低的口罩)使用,然后将该口罩的舒适度x2,如果这个口罩的不舒适度大于后面的,那么再排序,重复之前步骤,直到达到最多能忍受的不舒适度总和。
时间复杂度:排序的时间复杂度为O(NlogN),外层不清楚,总之超时了过不了。
可能的优化:口罩使用后不舒适度翻倍,然后用二分找到它的位置,将其插入。
参考代码:

#include<iostream>
#include<algorithm>
using namespace std;

const int N=1e5+10;
int a[N];

int main()
{
    int n,k;
    cin>>n>>k;
    for(int i=0;i<n;i++)
        cin>>a[i];
    sort(a,a+n);//对初始的不舒适度排序
    int cnt=0;//cnt记录天数
    while(k>0)
    {
        k-=a[0];//k就相当于是耐久值
        a[0]=a[0]*2;//不舒适度翻倍
        if(a[0]>a[1])//表明当前的位置不对了
            sort(a,a+n);
        cnt++;
    }
    cout<<cnt-1;
    return 0;
}

思路2:使用小根堆来存储,每次都是最小值出堆,使用后两倍入堆。
priority_queue<int,vector,greater> q;//小根堆,不加greater是大根堆
时间复杂度:O(NlogNlogk)
参考代码2:

#include<iostream>
#include<queue>//小根堆包含的头文件
using namespace std;

int main()
{
    int n,k;
    cin>>n>>k;
    priority_queue<int,vector<int>,greater<int>> q;//小根堆,不加greater是大根堆
    while(n--)
    {
        int x;
        cin>>x;
        q.push(x);//入堆
    }
    int cnt=0;//记录天数
    while(k>0)
    {
        int temp=q.top();//取堆顶元素即最小值
        q.pop();//将堆顶元素弹出
        k-=temp;
        q.push(temp*2);//使用后两倍入堆
        cnt++;
    }
    cout<<cnt-1;
    return 0;
}
D.小红的数组

知识点:排序、二分
思路:二分做法,先将数组从小到大排序,已知了x,那么整个数组就可以以k/x为分割线来分割区间。二分边界问题很多,实际应用中需要仔细甄别。
时间复杂度:O()
参考代码:

#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int N=3e5+10;
LL a[N];

int main()
{
    int n;
    LL k;
    cin>>n>>k;
    for(int i=0;i<n;i++)
        cin>>a[i];
    
    LL res1=0,res2=0,res3=0;
	sort(a,a+n);
    for(int i=0;i<n-1;i++)
        //a[i+1]是目前方案中的最小值
        //a[i]*a[i+1]<k意味着a[i]与后面所有的数的乘积都满足大于k
        if(a[i]*a[i+1]>k)
            res1+=n-i-1;//(n-1)-(i+1)+1
        else if(a[i]*a[n-1]<k)
            res3+=n-i-1;
        else
        {
            //lower_bound 查找不小于目标值的第一个数,参数(头,尾,x),返回值为指针
            //upper_bound 查找大于目标值的第一个数,找到的是右边界+1的位置
            int l=lower_bound(a+i+1,a+n,k/a[i])-a;//左边界
            int r=upper_bound(a+i+1,a+n,k/a[i])-a;//右边界+1
            //k能整除a[i]意味着存在k/a[i]这个数
            if(k%a[i]==0)
            {
                res2+=r-l;
                res1+=n-r;//(n-1)-r+1
                res3+=l-i-1;//(l-1)-(i+1)+1
            }
            //不能整除,l在小于的方案,r在大于的方案
            else
            {
                res1+=n-r;//(n-1)-r+1
                //l和r之间可能还会有一段相等的数,这一段应该都在小于方案
                res3+=r-i-1;//(r-1)-(i+1)+1
            }
        }

    cout<<res1<<' '<<res2<<' '<<res3;
    return 0;
}
E.小红的rpg游戏

知识点:最短路、枚举
思路:
参考代码:


F.小红的375
上一篇:41.函数应用:打印图形和数学计算


下一篇:有点干货 | Jdk1.8新特性实战篇(41个案例)