观前提醒:
笔试所有系列文章均是记录本人的笔试题思路与代码,从中得到的启发和从别人题解的学习到的地方,所以关于题目的解答,只是以本人能读懂为目标,如果大家觉得看不懂,那是正常的。如果对本文的某些知识有不同的观点,欢迎讨论。
题目链接:
第一题:简写单词_牛客题霸_牛客网
第二题:Fd(重做)
第三题:除2!
---------------------------------------------------我是分割线---------------------------------------------------------------
---------------------------------------------------我是分割线---------------------------------------------------------------
---------------------------------------------------我是分割线---------------------------------------------------------------
---------------------------------------------------我是分割线---------------------------------------------------------------
---------------------------------------------------我是分割线---------------------------------------------------------------
第一题
思路:
1)一道很简单的模拟题,属于是签到题的水平,大家直接模拟即可。
不过要注意观察例子,发现有的单词首字母是大写,有的是小写,讨论一下即可。
2)关于大小写转换,大家是直接使用ASC||转化,还是调用库函数【tolower/toupper函数】都可以。
代码:
#include <iostream>
#include <cstdio>
// #include<bit/stdc++.h>
using namespace std;
int main() {
string str="";
string s1="";
while(cin >> s1)
{
if(s1[0] >=97 && s1[0] <=122)
{
str+=(s1[0]-32);
continue;
}
str+=(s1[0]);
}
printf("%s\n",str.c_str());
return 0;
}
---------------------------------------------------我是分割线---------------------------------------------------------------
---------------------------------------------------我是分割线---------------------------------------------------------------
---------------------------------------------------我是分割线---------------------------------------------------------------
第二题
思路:
本题读完题,应该反应过来是一道滑动窗口的题目,但是我太久没做滑动窗口忘了,该如何出窗口,哭!下面正式分析。
1)暴力解法
读完题目,很明显我们可以使用双重循环解决这个问题,但是看一眼数据范围 10^7 O(N^2)的解法肯定是不行了,所以我们要对该解法优化。
我们观察发现,该数组的每个值大于0,那我们第一次遍历出我们的一个结果时,有必要将我们两个指针的每一个回到开头重新遍历一般吗,没有必要,因为重新开始,它也只能遍历到当前位置才有可能,大于目标值。
所以我们基于以上分析,我们可以明白它是符合滑动窗口的特征。
2)滑动窗口解法
我们要分析什么时候进窗口,什么时候出窗口,什么时候更新结果,什么时候停止滑动?
- 当right右移的时候,进窗口,将sum+=对应的值
- 当sum大于target的时候,我们就可以将left左移,但是这也是一个循环,防止只出一个数,无法满足sum<target。
- 当发现我们的窗口长度小于我们记录的长度的时候,就可以更新结果了。
- 当遍历完成后,就可以停止了。
代码:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int n=0,target=0;
cin>>n>>target;
vector<int> nums(n+1);
for(int i=1;i<=n;i++)
{
int y=0;
scanf("%d ",&y);
nums[i]=y;
}
int len=0x3f3f3f3f,right=1,left=1;
int retleft=-1,retright=-1;
int sum=0;
while(right <= n)
{
sum+=nums[right];
while(sum >=target)
{
if(right-left+1 < len) retleft=left,retright=right,len=right-left+1;
sum-=nums[left++];
}
right++;
}
printf("%d %d\n",retleft,retright);
return 0;
}
---------------------------------------------------我是分割线---------------------------------------------------------------
---------------------------------------------------我是分割线---------------------------------------------------------------
---------------------------------------------------我是分割线---------------------------------------------------------------
第三题
思路:
1)简单模拟+贪心(只对最大的偶数操作)+堆
读完题目,我们就有思路了,既然题目只对偶数操作,那么我们不就可以一直对最大的偶数进行操作,不就可以让数组的元素和最小吗?
关于记录最大的偶数,我们可以直接利用堆就可以。
代码:
#include<queue>;
#include<vector>;
#include<iostream>;
using namespace std;
int main()
{
int k=0,n=0;
cin>>n>>k;
long long sum=0;
priority_queue<int> heap;
for(int i=0;i<n;i++)
{
int x=0;
cin>>x;
if(x % 2 ==0)
heap.push(x);
else
sum+=x;
}
for(int i=0;i<k && !heap.empty();i++)
{
int y=heap.top();
y/=2;
heap.pop();
if(y %2 == 0)
heap.push(y);
else
sum+=y;
}
while(!heap.empty())
{
sum+=heap.top();
heap.pop();
}
printf("%lld\n",sum);
return 0;
}