比赛链接:
友情提示:
蓝桥杯的头文件,如果不是都记得,可以直接万能头文件 #include <bits/stdc++.h>, 不过有的时候,这样子会超时,之前做过一些题,卡时间,所以如果记得,尽可能把头文件个个都打出。
A题——钟表
送分题,直接手算即可,30:24:26 - 22:28:45 = 07:55:41 。
B题——青蛙爬井
简单题,直接暴力求解,因为那是刚好开着python,所以是用python写的。答案是:863。
代码如下:
sum = 0
up = 105
down = 35
h = 60405
for d in range(1,100000):
sum += up
if sum >= h:
print(d)
break
sum -= down
C题——倍数
简单题,用到一个思路,就是 1 到 n 有多少个是 m 倍数,个数为 n/m,所以这道题即:r/d - l/d,答案为:52573230519
代码如下:
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long r = 12302135942453, l = 1032, d = 234, res;
res = r/d - l/d;
cout << res << endl;
return 0;
}
E题——LIS
求LIS的常用两种方法,一种动态规划,复杂度O(n^2),一种就是改题目二分思想,复杂度O(nlogn),具体可以参考其他的博客学习。
如果实在不会,可以猜测,比如上面有一个二分法的函数,但其他都没用过,所以改行代码肯定是用,而且二分法有返回值,结合代码上下,发现没有定义 k ,所以这个调用二分法的返回值就是 k ,其他的三个参数就可以多试试看,比如前两个参数是二分法的范围,有可能是 0 到 n-1,也可能0 到 len,也可能len 到n-1,根据下面代码出现了len,所以有len的可能性更大。最后一个参数是要找的数,结合下面的代码,那就猜测是a[i] 。
所以这种代码填空的比较好得分。
答案:int k = find(0,len,a[i]);
F题——找质数
简单题,思路:先利用打表把所有素数找出来,然后从2开始判断,当 i 为素数 且 n-i 也为素数,那么这个就是答案,进行输出。而打表素数的方法,根据数据范围:1e6,所以要使用素数筛选法,不然会导致超时。
AC代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
int p[maxn];
void init()
{
memset(p,0,sizeof(p));
for(int i = 2;i*i<maxn;i++)
{
if(p[i]==0)
{
for(int j = i*2;j<maxn;j+=i)
p[j] = 1;
}
}
return;
}
int main()
{
init();
int t;
scanf("%d",&t);
int n;
while(t--)
{
scanf("%d",&n);
for(int i = 2;i < n;i++)
{
if(p[i]==0 && p[n-i]==0)
{
printf("%d %d\n",i,n-i);
break;
}
}
}
return 0;
}
G题——后缀字符串
重点,要会C++的string 用法,以及 STL中的 map 容器使用。
拿到题目的第一眼,就是利用模拟暴力求解:
将该字符和其他所有字符比较,首先,能把当前字符做后缀的,说明字符串长度更长,所以可以先判断字符串长度比较,如果比当前的小,说明不可能;如果其他的字符串长度比当前要拿来做后缀的长度长的话,比如现在是ba,而我们到了aba,从直观看,aba(记为s[j])是以ba(记为s[i])为后缀的,我们用两个长度作差得 1(记为x),然后以 s[i] 长度为循环,y 从0 到 长度-1,比较s[i][y] 与 s[j][y+x] ,如果都相等,那就是后缀,如果中间有不同的,那就不是后缀。
但是这样子计算复杂度是O(n^2*10),而一秒大概 可以做 4e8 次循环,所以对于后百分之50的数据,无法通过。
那就想到了关于C++的STL中有一个map容器,通过map<string, int> mp,将字符串与数进行匹配,这样子,对于ba,我们就可以mp[ba]++,mp[a]++ ,对于每一个字符串都这样子从头到尾,这样子表示以这个为后缀的出现过了一次,那么这样子的复杂度大概为O(n*10),就不会超时,具体的map学习可以去参考其他博客,也可以参考书籍,要会使用。
AC代码100%——利用map容器:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
string s[maxn];
int main()
{
int n;
scanf("%d",&n);
map<string, int> mp;
for (int i = 0; i < n; i++) {
cin >> s[i];
for (int j = 0; j < s[i].length(); j++) {
mp[s[i].substr(j)]++;
}
}
for (int i = 0; i < n; i++) {
cout << mp[s[i]] << endl;
}
return 0;
}
50%数据通过代码——模拟暴力:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
string s[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i = 0;i < n;i++)
{
cin >> s[i];
//cout << s[i].length() << endl;
}
int res;
bool yes;
int x;
for(int i = 0;i < n;i++)
{
res = 1;
for(int j = 0;j<n;j++)
{
if(j==i)
continue;
x = s[j].length()-s[i].length();
//cout << x << endl;
if(x<0)
continue;
yes = true;
for(int y = 0;y<s[i].length();y++)
{
if(s[j][y+x]!=s[i][y])
{
yes = false;
break;
}
}
if(yes)
res++;
}
printf("%d\n",res);
}
return 0;
}
H题——轻重搭配
模拟题,因为要是 x 与至少 2x 搭配,那我们就先将输入的体重数据进行排序,从小到大进行排序
思路:用一个数组记录开始谁和谁能匹配,这样子两个人一张票,最后遍历这个记录数组,没有匹配的就要一人一张票。
而谁和谁能匹配,就是从最小的开始找,将数据分为前一半和后一半,所以从前一半的开始(代码中记为 l) 和 后一半的开始(代码中记为 r) 开始找匹配,匹配成功,同时加1,然后门票加1(并且在记录数组mark中记录这两个人已经是匹配成功了);如果不成功,则后一半往后找,r++,注意一个地方,else那里最后结束了有一个 l--,是为了平衡for循环的 l++,因为匹配没成功,所以 l 不能变动。然后另外有一个数组记录谁匹配过,最后 for 循环遍历该数组,没有能匹配的,说明都要一人买一张票。
举例:样例的 1 3 5 5 7 9,分了两部分:1 3 5 和 5 7 9, 1可以和 5匹配,这样子标记(这里用红色说明),此时变为:1 3 5 和 5 7 9,票数为1。然后 3 和 7 匹配,变为1 3 5 和 5 7 9,票数为2。然后都往后移一位,5 和 9不能匹配,且往后没有数了,结束。
然后遍历数组标记 1 3 5 5 7 9 发现有两个无法匹配,所以最后票数为 4 。
AC代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5+5;
int a[maxn];
int mark[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i = 0;i < n;i++)
scanf("%d",a+i);
memset(mark,0,sizeof(mark));
sort(a,a+n);
int res = 0;
int flag = 1;
for(int r = n/2,l = 0;l<n/2 && r<n;l++)
{
if(a[l]*2<=a[r])
{
res++;
mark[r] = mark[l] = 1;
r++;
}
else
{
while(a[l]*2>a[r])
{
r++;
if(r>=n)
{
flag = 0;
break;
}
}
l--;
}
if(flag==0)
break;
}
for(int i = 0;i < n;i++)
{
if(mark[i]==0)
res++;
}
printf("%d\n",res);
return 0;
}
J题——蒜厂年会
这道题为:首尾相连的序列,求n最大的连续子序列和
思路:
1、如果子序列的最大和在 1 到 n 的范围内,直接输出最大和即可
2、如果子序列的最大和横跨了尾部和头部,则先求出连续的最小子序列和然后用总和减去最小子串和就是最大子串和
所以求 1 到 n 中的最大和最小的连续子序列和(记为Mx,和Mi),然后输出 Mx 和 sum-Mi 中的最大值即可。
AC代码如下:
#include <bits/stdc++.h>
# define MAXN 200005
# define INFI 0x3f3f3f3f
using namespace std;
long long sum,mx=0,mi=0,Mx=0,Mi=0;
long long num[MAXN],n;
int main()
{
// freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
cin >> n;
memset(num,0,sizeof(num));
Mx = -INFI;
Mi = INFI;
mx = mi = sum = 0;
long long tmp = 0;
for(int i=0; i<n; ++i)
{
cin >> num[i];
sum += num[i];
mx += num[i];
mi += num[i];
Mx = max(Mx,mx);
Mi = min(Mi,mi);
if(mi > 0) mi = 0;
if(mx < 0) mx = 0;
}
cout << max(sum-Mi,Mx) <<endl;
return 0;
}