【解题思路】
bit是位,B是字节,1B = 8bit,除此之外任意两个都是1024的距离。
所以手机的4GB内存就是 4 ∗ 2 30 = 2 32 4*2^{30} = 2^{32} 4∗230=232个字节(B)
【代码】
#include
using namespace std;
int main(){
int res = 15.125*1024;
printf("%d", res);
return 0;
}
【解题思路】
填空题怎么方便怎么来,枚举。
【代码】
#include
using namespace std;
int main(){
int n = 1200000;
int cnt = 0;
for(int i=1; i<=n; i++){
if(n%i == 0){
cnt++;
}
}
printf("%d", cnt);
return 0;
}
【解题思路】
有: n 0 = ( n − n 1 + 1 ) / 2 n0 = (n-n1+1)/2 n0=(n−n1+1)/2
要使n0最大,n1要最小,则n1 = 0
所以: n 0 = ( n + 1 ) / 2 n0 = (n+1)/2 n0=(n+1)/2
【代码】
#include
using namespace std;
int main(){
int n = 2019;
printf("%d", (n+1)/2);
return 0;
}
【解题思路】
枚举1~2019,取每个数的每一位判断是否为9,遇到九就不用继续判断剩余的位数了。
【代码】
#include
using namespace std;
bool hasEight(int n){
bool flag = false;
while(n>0){
if(n%10 == 9){
flag = true;
break;
}
n /= 10;
}
return flag;
}
int main(){
int n = 2019, ans = 0;
for(int i=1; i<=2019; i++){
if(hasEight(i))
ans++;
}
printf("%d", ans);
return 0;
}
【解题思路】
最大数只有7位,n最大1000000(10^6),每一个数枚举位数判断复杂度是O(1)的,n个数O(7n),可以枚举。
【代码】
#include
using namespace std;
bool ok(int n){
if(n < 10)
return true;
bool flag = true;
int x = n%10;
n /= 10;
while(n>0){
if(n%10 > x){
flag = false;
break;
}
//更新x和n
x = n % 10;
n /= 10;
}
return flag;
}
int main(){
int n;
scanf("%d", &n);
int ans = 0;
for(int i=1; i<=n; i++){
if(ok(i)){
ans++;
}
}
printf("%d", ans);
return 0;
}
【解题思路】
枚举每一个数,看左边有没有比它小的 && 右边有没有比它大的,时间复杂度O(n^2),不会超时。
【代码】
#include
using namespace std;
const int maxn = 10010;
int num[maxn];
int main(){
int n;
scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%d", &num[i]);
}
int ans = 0, x;
for(int i=1; i<n-1; i++){
x = num[i];
bool hasSmall = false, hasBig = false;
for(int j=0; j<i; j++){
if(num[j] < x){
hasSmall = true;
break;
}
}
for(int j=i+1; j<n; j++){
if(num[j] > x){
hasBig = true;
break;
}
}
if(hasSmall && hasBig){
ans++;
}
}
printf("%d", ans);
return 0;
}
【解题思路】
因为要能把单词划分为辅音元音辅音元音四个部分,只要从头到尾扫描一边字符串即可,时间复杂度为O(n),n为字符串长度。
我是这样做的,设置一个标识last表示当前字母的前一个字母是否是元音,初始值为输入字符串的第一个字母是否为元音,如果是,last = true,这是程序可以直接退出了,因为第一部分必须是辅音。
设置idx,表明当前字母处于第几部分。
扫描过程:
如果第一个字母是辅音,last = false,然后从第二个字母开始,如果:
最后如果idx为4表明刚好符合要求的四段,输出yes,反之输出no
【例如】 lanqiao
【代码】
#include
#include
using namespace std;
string vowel = "aeiou";
bool isVowel(char ch){
bool flag = false;
for(int i=0; i<vowel.length(); i++){
if(vowel[i] == ch){
flag = true;
break;
}
}
return flag;
}
int main(){
string str;
cin>>str;
bool last = false;//前一个字母是元音为true
if(isVowel(str[0])) last = true;
//辅音元音辅音元音
int idx = 1;
if(last){
printf("no");
}
else{
for(int i=1; i<str.length(); i++){
if(last){
//如果前一个是元音并且当前字母也是元音,什么都不做
//如果当前字母是辅音,idx++;
if(!isVowel(str[i])){
idx++;
last = false;
}
}
else{
//前一个是辅音
//当前是元音,idx++
if(isVowel(str[i])){
idx++;
last = true;
}
}
}
if(idx == 4){
printf("yes");
}
else{
printf("no");
}
}
return 0;
}
【解题思路】
这是一个典型的BFS题目,总共有nm个位置,习惯说结点,那么最多每个结点都入队一次,时间复杂度为O(nm)
结点用结构体表示,除了结点的坐标,还需要记录该结点是第几个月长出来的,也就是层数。
struct node{
int x, y;
int layer;
};
用到的变量有:
上述都放在全局,在竞赛时这样很方便,不会涉及到引用之类的,没啥坏处,所以能放在全局我就不会传参。
读入数据时,如果是“g”就将matrix[i][j]设为true,把该结点入队(注意层数设置为0)并设置为已入队,然后进行BFS。
BFS时取出队首元素,如果该元素的layer == k,就直接退出了(只看第k月草的长势情况),否则枚举它周围的结点,并将层数设置为layer+1,然后如果没入过队并且没出界,就加入队列。
注意不需要管该地现在有没有草,都需要入队。
【代码】
#include
#include
using namespace std;
const int maxn = 1010;
struct node{
int x, y;
int layer;
};
//增量矩阵
int X[4] = {0, 0, 1, -1};
int Y[4] = {1, -1, 0, 0};
bool matrix[maxn][maxn];//matrix[i][j] = true表示(i, j)处有草
bool inq[maxn][maxn] = {false};//检查坐标为(i, j)的点是否已经入过队列
queue<node> q;
int n, m, k;
bool judge(int i, int j){
//越界
if(i<0||i>=n||j<0||j>=m) return false;
//入过队
if(inq[i][j]) return false;
return true;
}
void BFS(){
while(!q.empty()){
node top = q.front();
q.pop();
if(top.layer == k){
break;
}
node temp;
temp.layer = top.layer + 1; //层数为父节点加1
//枚举四个方向
for(int i=0; i<4; i++){
temp.x = top.x + X[i];
temp.y = top.y + Y[i];
if(judge(temp.x, temp.y)){
matrix[temp.x][temp.y] = true;
inq[temp.x][temp.y] = true;
q.push(temp);
}
}
}
}
int main(){
scanf("%d%d", &n, &m);
getchar();
char ch;
node temp;
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
scanf("%c", &ch);
if(ch == '.') matrix[i][j] = false;
else{
matrix[i][j] = true;
temp.x = i;
temp.y = j;
temp.layer = 0;//一开始就种了,相当于第0个月的情况
q.push(temp);
inq[i][j] = true;
}
}
getchar();//一行读完了记得读掉空行
}
scanf("%d", &k);
BFS();
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
if(matrix[i][j])
printf("g");
else
printf(".");
}
printf("\n");
}
return 0;
}
【解题思路】
蓝桥杯总会考一题类似这样的搜索问题。题意清楚但是又根本感觉无从下手。这种时候要尽力想办法一层一层剥开来考虑,首先想一个能表达出结果的方法(我觉得有点像动态规划找表达式的感觉),然后想办法怎么才能让这个表达规模变小(好像又有点分治的意思),直到能求出答案。
所以用f(i, j)表示第一个数是i,第二个数是1~j的序列个数,结果可以表达为f[n, n),那表达式是: f ( i , j ) = f ( i , j − 1 ) + 1 + f ( j , a b s ( i − j ) − 1 ) f(i, j) = f(i, j-1)+1+f(j, abs(i-j)-1) f(i,j)=f(i,j−1)+1+f(j,abs(i−j)−1)
就是一次减小一层规模,展开一层的感觉,第一项是剩余的第一个数是i,第二个是1~j-1的序列个数,第二项是展开的那一层,也就是第一个数是i,第二个数是j的序列个数,那么有两种:
【代码】
#include
using namespace std;
const int maxn = 1010;
const int MOD = 10000;
int mem[maxn][maxn];
int n;
int dfs(int i, int j){
//f(i,j)表示前一个数是i,当前数是1到j的合法序列的个数
if(j <= 0) return 0;
if(mem[i][j] != 0) return mem[i][j];
//展开一层(展开前一个数是i,当前数是j的合法序列这层,个数为 1 + dfs(i, abs(i - j) - 1))
else return mem[i][j] = (dfs(i, j-1) + 1 + dfs(j, abs(i-j)-1))%MOD;
}
int main(){
scanf("%d", &n);
int res = dfs(n, n);
printf("%d", res);
return 0;
}
【解题思路】
一看题:直接结构体两次排序,这么简单啊。
果然是我想多了…
果然看懂题目才是最重要的,题目表达的是:他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。
并不是找前m大的数按照输入顺序输出,而是找字典序最大的m个数组成的序列。
举个栗子:
6 3
3 4 8 7 1 2
如果只是找前m大的数,那么(结构体先按好看值排序再按索引排序)会输出:
4 8 7
但题目的意思需要输出:
8 7 2
因为即使第一个序列的总好看值更大,但第二个序列才满足了第一个节目尽可能好看,也就是字典序大的要求。
那么可以使用two pointers来解决(找的是区间最值):
两个指针p1, p2分别指向区间的首尾,初始时p1 = 0, p2 = n-m, 因为第一个数只能在这个区间内,如果p2再大,就不能保证总共能取到m个数。
遍历[p1, p2]范围内的好看值数组,用pm指示区间内最大元素的下标,MAX指示区间内最大的元素(记录好找最大值),输出MAX。
更新区间 p 1 = p m + 1 , p 2 = p 2 + 1 p1 = pm + 1, p2 = p2 + 1 p1=pm+1,p2=p2+1 直到 p 1 = = p 2 p1 == p2 p1==p2, 或者 p 2 = = n p2 == n p2==n
p 1 = = p 2 p1 == p2 p1==p2的情况说明区间内就一个数,直接输出数组后的全部数就行了,也就是节目都得上,因为初始时p2的取值就使得后面的数只有m-1个了。
还是这个栗子:
6 3
3 4 8 7 1 2
最终得到了8、7、2,这是六个数中取三个数的序列中字典序最大的一个。
【代码】
复杂度是O(n^2),会超时,我这就去学习ST和线段树。
#include
#include
using namespace std;
const int maxn = 100010;
int show[maxn];
int main(){
int n, m;
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++){
scanf("%d", &show[i]);
}
//在n个数中找出字典序最大的m个数的序列
int p1 = 0, p2 = n-m, pm;
while(p1 < p2 && p2 < n){
int MAX = -1;
for(int i=p1; i<=p2; i++){
if(show[i] > MAX){
MAX = show[i];
pm = i;
}
}
printf("%d ", show[pm]);
//更新区间
p1 = pm+1;
p2++;
}
//p1和p2相等,说明后面的节目都被选中了
if(p2 < n){
for(int i=p2; i<n; i++){
printf("%d ", show[i]);
}
}
return 0;
}
感觉蓝桥杯很爱考数学问题。