大一新生备战2020蓝桥杯

纵然是瞬间 提交于 2020-03-08 18:43:32

一:错误票据

关键字:排序
题目:

资源限制时间限制:1.0s 内存限制:256.0MB问题描述

某涉密单位下发了某种票据,并要在年终全部收回。
每张票据有唯一的ID号。全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。
因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。
你的任务是通过编程,找出断号的ID和重号的ID。
假设断号不可能发生在最大和最小号。

输入格式

要求程序首先输入一个整数N(N<100)表示后面数据行数。
接着读入N行数据。
每行数据长度不等,是用空格分开的若干个(不大于100个)正整数(不大于100000),请注意行内和行末可能有多余的空格,你的程序需要能处理这些空格。
每个整数代表一个ID号。

输出格式

要求程序输出1行,含两个整数m n,用空格分隔。
其中,m表示断号ID,n表示重号ID

样例输入1
2

5 6 8 11 9

10 12 9
样例输出1
7 9
样例输入2
6

164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196

172 189 127 107 112 192 103 131 133 169 158

128 102 110 148 139 157 140 195 197

185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190

149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188

113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119
样例输出2
105 120
解答:

#include <iostream> 
#include <sstream>
#include<algorithm>
using namespace std;
const int MaxN = 10000;
int line;
int data[MaxN];
void s2i(string& str, int & num) {//字符串转为整数
 stringstream ss;
 ss << str;
 ss >> num;
}
int main(int atgc, const char* argv[]) {
 scanf("%d", &line);
 getchar();
 int index = 0;
 for (int i = 0; i < line; ++i) {
  string s;
  getline(cin, s);
  istringstream iss(s);
  string tmp;
  while (getline(iss, tmp, ' ')) {
   s2i(tmp, data[index++]);
  }
 }
 //最终index就是数据的个数 
 //cout << index << endl;
 //排序
 sort(data, data + index);
 int a, b;
 for (int i = 0; i < index; ++i) {
  if (data[i] == data[i - 1] + 2) a = data[i] - 1;
  if (data[i] == data[i - 1]) b = data[i];
 }
 printf("%d %d", a, b);
 return 0;
}

涉及的未了解到的内容:
1:sort排序问题。
2:输入输出流
3:getline()

第一个问题:sort排序问题在数组中的解决
要sort函数,必须包含头文件:#include <algorithm>
语法描述为:Sort(start,end,排序方法)
(1)第一个是要排序的数组的起始地址。
(2)第二个是结束的地址(最后一位要排序的地址的下一地址)
(3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。
可以参考:sort排序的用法
第二个问题:输入输出流的应用
请直接参考文章:输入输出流的简单介绍

第三个问题:getline()的应用
请直接参考:getline()的简单介绍

排序问题

请参考:包含所有排序经典排序算法
快速排序可参考这个:快速排序
或者:快速排序
冒泡排序和选择排序大一上就接触了,如果忘了再去看看。
插入排序参考:插入排序
归并排序:

#include<iostream>
#include<algorithm>
using namespace std;
void merge(int* data, int start, int end, int* result)//在排序前,建立了两个数组,data和result,data用于排序交换,result用于最后的并
{
    int left_length = (end - start + 1) / 2 + 1;
    int left_index = start;
    int right_index = start + left_length;
    int result_index = start;
    while (left_index < start + left_length && right_index < end + 1)  //store data into new array
    {
        if (data[left_index] <= data[right_index])
            result[result_index++] = data[left_index++];
        else
            result[result_index++] = data[right_index++];
    }
    while (left_index < start + left_length)
        result[result_index++] = data[left_index++];
    while (right_index < end + 1)
        result[result_index++] = data[right_index++];
}
void merge_sort(int* data, int start, int end, int* result)
{
    if (1 == end - start)   //last only two elements
    {
        if (data[start] > data[end])
        {
            int temp = data[start];
            data[start] = data[end];
            data[end] = temp;
        }
        return ;
    }
    else if (end == start)
        return; //last one element then there is no need to sort;
    else {
        //continue to divide the interval
        merge_sort(data, start, (end - start + 1) / 2 + start, result);//左边归并排序,使得左子序列有序
        merge_sort(data, (end - start + 1) / 2 + start + 1, end, result);//右边归并排序,使得右子序列有序
        //start to merge sorted data
        merge(data, start, end, result);//将两个有序子数组合并操作
        for (int i = start; i <= end; ++i)
        {
            data[i] = result[i];
        }
    }
}
//example
int main()
{
    int data[] = { 5,3,6,7,3,2,7,9,8,6,34,32,5,4,43,12,37 };
    int length = 17;
    int result[17];
    cout << "before sorted:" << '\n';
    for (int i = 0; i < length; i++)
        cout << data[i] << ' ';
    cout << '\n'
        << "after sorted:" << '\n';
    merge_sort(data, 0, length - 1, result);
    for (int i = 0; i < length; i++)
        cout << result[i] << ' ';
    return 0;
}

希尔排序:希尔排序


#include<iostream>
using namespace std;
 void ShellSort(int* h, size_t len)
 {
       if (h == NULL) return;
        if (len <= 1) return;
             for (int div = len / 2; div >= 1; div /= 2)//div为步长每次减为原来的一半,就是一半半分组
             for (int k = 0; k < div; ++k)//多少次
             for (int i = div + k; i < len; i += div)//让i为步长加当前组的首元素就是当前组的第二个元素,然后第三个,第四个。。。
             for (int j = i; j > k; j -= div)//j为当前组的第二个元素,j=j-div就回到了当前组第一个元素,所以下面肯定执行一次
               if (h[j] < h[j - div]) swap(h[j], h[j - div]);//这次执行为了判断该组的哪个元素大
                        else break;
        return;
    }
 void main() {
     int arr[10] = { 1,2,3,9,8,7,6,5,4,0 };
     ShellSort(arr,10);
     for(int i=0;i<10;i++)
     cout << arr[i] << endl;
 }

堆排序:堆排序

二:翻硬币

问题描述

小明正在玩一个“翻硬币”的游戏。
桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:**oo***oooo
如果同时翻转左边的两个硬币,则变为:oooo***oooo
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作,那么要求:

输入格式

两行等长的字符串,分别表示初始状态和要达到的目标状态。每行的长度<1000

输出格式

一个整数,表示最小操作步数。

样例输入1

**********
o****o****

样例输出1

5

样例输入2

*o**o***o***
*o***o**o***

样例输出2

1

代码:


#include<iostream>
#include<string>
using namespace std;
int main(int argc,const char *argv[]) {
    string src;
    string target;
    getline(cin,src);
    getline(cin,target);
    int ans = 0;
    int n = src.length();
    int start = -1;
    for (int i = 0; i < n; ++i) {
        if (src[i] != target[i]) {
            if (start == -1) {//还没标记第一个位置
                start = i;
            }
            else//第一个位置已标记,现在找到第二个位置
            {
                ans += (i - start);
                start = -1;
            }
        }
    }
    cout << ans << endl;
    return 0;
}

涉及问题:
贪心算法
图解:表情包图解
例子:C++
java

三:带分数

#include<bits/stdc++.h>
using namespace std;
int fun(const char* arr, int pos, int len) {
    int ans = 0;
    int t = 1;
    for (int i = pos + len - 1; i >= pos; --i) {
        ans += (arr[i] - '0') * t;
        t *= 10;
    }
    return ans;
}
int main() {
    int n, count = 0;
    string ss = "123456789";
    cin >> n;
    do {
        const char* s = ss.c_str();
        for (int i = 1; i <= 7; i++) {
            int a = fun(s, 0, i);
            if (a >= n) {
                break;
            }
            for (int j = 1; j <= 9 - i - 1; j++) {
                int b = fun(s, i, j);
                int c = fun(s, j + i, 9 - i - j);
                 if (b % c != 0 || (b / c + a) != n) {        
                    continue;
                }
                count++;
            }
        }
    } while (next_permutation(ss.begin(), ss.end()));
    cout << count;
    return 0;
}

全排列:全排列描述

李白打酒

话说大诗人李白,一生好饮。幸好他从不开车。 一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱: 无事街上走,提壶去打酒。 逢店加一倍,遇花喝一斗。 这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。

请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。

注意:通过浏览器提交答案。答案是个整数。不要书写任何多余的内容。

int ans = 0;
void f(int dian,int hua,int jiu) {
    if (dian == 0 && hua == 0 && jiu == 1)
        ans++;
   if(dian>0) f(dian - 1, hua, jiu * 2);
    if(hua>0)f(dian, hua - 1, jiu - 1);
}
int main() {
    f(5, 9, 2);
    cout << ans << endl;
}

学会这种查找次数的方法

六角填数

如图所示六角形中,填入1~12的数字。

使得每条直线上的数字之和都相同。

图中,已经替你填好了3个数字,请你计算星号位置所代表的数字是多少?

请通过浏览器提交答案,不要填写多余的内容。
在这里插入图片描述

#include<iostream>
#include <vector>
#include <algorithm>
using namespace std;
void check(vector<int>v) {
    int r1 = 1 + v[0] + v[3] + v[5];
    int r2 = 1 + v[1] + v[4] + v[8];
    int r3 = 8 + v[0] + v[1] + v[2];
    int r4 = 11 + v[3] + v[6];
    int r5 = 3 + v[2] + v[4] + v[7];
    int r6 = v[5] + v[6] + v[7] + v[8];
    if (r1 == r2 && r2 == r3 && r3 == r4 && r4 == r5 && r5 == r6) {
        for (int i = 0; i < 9; ++i) {
            cout << v[i] << " " << endl;
        }
    }
}
int main() {
    vector<int>v;
    v.push_back(2);
    for (int i = 4; i <= 7; ++i) {
        v.push_back(i);
    }
    for (int i = 9; i <= 12; ++i) {
        v.push_back(i);
    }
    do {
        check(v);
    } while (next_permutation(v.begin(), v.end()));
    return 0;
}

未学到的东西:
1:集合vector:vector的运用
2:全排列全排列的运用

地宫取宝

问题描述
  X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。
  地宫的入口在左上角,出口在右下角。
  小明被带到地宫的入口,国王要求他只能向右或向下行走。
  走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。
  当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。
  请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。
输入格式
  输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)
  接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值
输出格式
  要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。
样例输入
2 2 2
1 2
2 1
样例输出
2
样例输入
2 3 2
1 2 3
2 1 5
样例输出
14
代码:

#include<iostream>
using namespace std;
const int MOD = 100000007;
int n, m, k;
int data[50][50];
long long ans;
void dfs(int x, int y, int max, int cnt) {
    if (x == n || y == m)
        return;
    int cur = data[x][y];
    if (x == n - 1 && y == m - 1)//已经面琳最后一个格子
    {
        if (cnt == k|| (cnt == k - 1 && cur > max)) {
            ans++; 
            if (ans > MOD)
                ans %= MOD;
        }
        if (cnt == k - 1 && cur > max)ans++;
    }
    if (cur > max) {//可以取这个物品
        dfs(x, y + 1, cur, cnt + 1);
        dfs(x+1, y, cur, cnt + 1);
    }
        //对于价值较小或者价值大但不去取的情况下
        dfs(x, y + 1, max, cnt);
        dfs(x + 1, y, max, cnt);
}

或者使用记忆性搜索

#include<iostream>
#include<cstring>
using namespace std;
const int MOD = 100000007;
int n, m, k;
int data[50][50];
long long cache[50][50][13][12];
long long ans;
long long  dfs(int x, int y, int max, int cnt) {
    //  查缓存
    if (cache[x][y][max][cnt]!= -1)
        return cache[x][y][max][cnt];
    long long ans = 0;
    if (x == n || y == m||cnt>k)
        return;
    int cur = data[x][y];
    if (x == n - 1 && y == m - 1)//已经面琳最后一个格子
    {
        if (cnt == k|| (cnt == k - 1 && cur > max)) {
            ans++; 
            if (ans > MOD)
                ans %= MOD;
        }
        return ans;
    }
    
    if (cur > max) {//可以取这个物品
       ans+= dfs(x, y + 1, cur, cnt + 1);
        ans+=dfs(x+1, y, cur, cnt + 1);
    }
        //对于价值较小或者价值大但不去取的情况下
        ans+=dfs(x, y + 1, max, cnt);
        ans+=dfs(x + 1, y, max, cnt);
        cache[x][y][max][cnt]=ans% MOD;
        return cache[x][y][max][cnt];
}
int main() {
    scanf("%d %d %d",&n,&m,&k);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            scanf("%d", &data[i][j]);
        }
    }
   // dfs(0, 0, -1, 0);//第一个点的价值可能是0
    memset(cache, -1, sizeof(cache));
    printf("%lli\n",dfs(0,0,-1,0));
    return 0;
}

记忆性搜索:记忆性算法总结

小朋友排队

代码:

int lowbit(int n) {
    return n - (n & (n - 1));
}
//原始数组的i位置增加v后
void updata(int n, int i, int v, int c[]) {
    int lb = lowbit(i);
    for (int k = i; k <= n; k += lowbit(k)) {
        c[k] += v;
    }
}
int getSum(int c[], int i) {
    int sum = 0;
    for (int k = i; k >= 1; k -= lowbit(k)) {
        sum += c[k];
    }
    return sum;
}
int main() {
    int n;
    int count;
    cin >> n;
    int h[100000],c[100000+1];
    int cnt[100000];//记录每个孩子的交换次数
    memset(cnt, 0, sizeof(cnt));
    int maxH = -1;
    for (int i = 0; i < n; ++i) {
        cin >> h[i];
        if (h[j] > maxH)maxH = h[j];
    }
    int c[100000 + 1];
    memset(c, 0, sizeof(c));
    for (int j = 0; j < n; ++j) {
        updata(n + 1, h[j] + 1, 1, c);//在相应位置计数变为1,其实就是用树状数组维护数组出现的个数
    //每更新一次
        int sum = getSum(c, h[j] + 1);//小于等于h[j]+1
        cnt[j]+=(j + 1) - sum;//得到的就是当前数据左侧比数据大的数的个数
    }
    memset(c, 0, sizeof(c));
    for (int j = n-1; j >=0; --j) {
        updata(n + 1, h[j] + 1, 1, c);//在相应位置计数变为1,其实就是用树状数组维护数组出现的个数
          cnt[j] += getSum(c,h[j]);
    }
    long long ans = 0;
    for (int i = 0; i < n; ++i) {
        ans += (cnt[i] * (cnt[i] + 1) / 2);
    }
    cout << ans<<endl;
    return 0;
}

树状数组:树状数组

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!