1.基德的神秘冒险 - 蓝桥云课 (lanqiao.cn)
我天呢。。。大清早就给我当头一棒TAT
这个呢。。我还没有理解的很透彻,所以只能对着代码写理解了 但我觉得这是一个很有意思的题目,辣么四四吧~~
先把石头从大到小进行排序
再用一个前缀和数组,把从第1块到第i块的所有作为最小值的组合数加起来
pre[i] = pre[i-1] + ((N- i) * (N - i - 1)/2 )
举例子一下就是第1块石头作为最小值的时候,另外两块从剩下的(N-i)块选择(这里也就是两块),组合数共有C(N-i, 2),即(N-i)*(N-i-1)/2块。假设总共有8块石头,当第5块石头作为最小值的时候,另外2块从剩下4块里面选,有C(8-5, 2)种组合数。
所以说前缀和数组pre存储了第1块到第i块石碑中任意一块为最小值得“三重石”得总组合数,s[i]存储得是从第一块到第i块石碑中,以第i块为最最小值得“三重石”的总组合数。
那么pre数组里面存储的是组合数,它的下标才是石碑;当我们要查找力量第K小的数值时,其实就是找组合数刚好达到或大于K的石碑(不能比K小啊)由于pre是前缀和数组,在这个位置之前的组合数是小于K的,而从这个位置开始,组合数才大于等于K,那么这个位置就是我们要找的石碑,我们求它的下标,最后要返回的是石碑上的数字。
lower_boudn函数返回的是一个迭代器,指向pre数组中第一个不小于(大于等于)K的元素,得出这个元素在pre数组中的索引 i(通过这个迭代器减去s数组的起始地址)我们可以得到这个元素在s数组中的索引 i,然后去石头数组里面找,就可以找到三重石中第K小的石碑。
芝士点:
- 迭代器
是一种检查容器内元素并遍历元素的数据类型,通常用于对C++各种容器内元素的访问,但不同的容器有不同的迭代器,初学者可以将迭代器理解为指针。
- lower_bound函数
lower_bound(first, last, target) / lower_bound(a, a+n, target) // a是数组
在[first, last)区间中二分查找第一个大于等于target的元素,返回的是last元素地址, 将其减去数组首元素地址可以得到该元素的下标,注意找的是第一个大于等于target的元素,如果没有相等的值,就会返回大于它的值,数组一定要是排好序的数组,因为这里面是二分查找。
#include <bits/stdc++.h>
using namespace std;
const int C = 10e5 + 10;
long long N, Q, K;
long long A[C],pre[C];
int main()
{
cin >> N >> Q;
for(int i = 1; i <= N; i++){
cin >> A[i];
}
sort(A+1, A+1+N);
for(int i = 1; i <= N; i++){
pre[i] = pre[i-1] + ((N-i)*(N-i-1)/2);
}
while(Q--){
cin >> K;
cout << A[lower_bound(pre, pre+N+1,K) - pre] << endl;
}
return 0;
}
2. 01小游戏 - 蓝桥云课 (lanqiao.cn)
这个很简单啊 为什么我当时没做出啊 为什么为什么 我不寄丢啊~~~~哈哈哈哈哈哈哈哈哈深井冰
就是这么写啊
#include <iostream>
using namespace std;
const int N = 20e5 + 50;
long long n, q;
int main()
{
int a = 0, b = 0;
string s ;
cin >> n >> q;
cin >> s;
int position = 0, repeat = 0;
while(q--){
cin >> a;
if(a == 1){
position = s.find('1') + 1;
cout << position << endl;
}
else{
cin >> b;
if(s[b-1] == '1')
s[b-1] = '0';
else
s[b-1] = '1';
}
}
return 0;
}
我知道了 是因为我不知道find()函数
芝士点:
find()函数:
- string类的find()函数
s.find(str, start, count);
str为要查找的子串/ 字符数组/ 字符;start为查找的起始位置;count为要查找的字符个数。
!!注意!!:
1. 在字符串中查找子串或者字符,返回第一个匹配的位置,没有则返回string::npos(强转int类型-1)。返回的是下标啊下标。
2. find()函数只能查找字串或字符在字符串中第一次出现的位置,如果想查找子串或字符在字符串。中所有出现的位置,可以使用循环结构和find()函数的第二个参数(查找起始位置) 实现
3. find()函数是区分大小写的
4. 是完全匹配啊完全匹配
- <algorithm>头文件下的find()函数
!!注意!!:
InputIterator find (InputIterator first, InputIterator last, const T& val);
1. first和last为输入迭代器,用于指定该函数查找的范围,是一个前闭后开的区间,val为要查找的目标元素,指向范围内搜索元素的第一次出现,如果没有找到目标元素,则返回last,返回最后一个元素
2. <algorithm>头文件下的find()函数是一个通用的算法,可以在任何容器中查找指定元素,,返回一个迭代器指向的第一个匹配的元素,它返回的是地址,想要知道下标需要用distance()计算
3. 也是只返回第一个等于val的元素,想查找所有需要用while打配合
以上多数参考博主番茄猫番茄毛,TA写的可详细了
拓展:
- find_first_of() 查找子串中的某个字符最先出现的位置(非全匹配)
- find_last_of() 这个函数与find_first_of()功能差不多,只不过find_first_of()是从字符串的前面往后面搜索,而 find_last_of()是从字符串的后面往前面搜索(非全匹配)
- rfind() 反向查找字符串,即找到最后一个与子串匹配的位置(全匹配)(从前往后搜索)
- find_first_not_of() 找到第一个不与子串匹配的位置(非全匹配)
私密马赛 这个也参考了别人的呢 哎哟 我觉得这个也不难啊,但是我为什么就是想不到啊
方法一:
把输入全都存入到一个一维数组中去,从大到小排序,然后再遍历,如果前一个值与后一个值的差大于一那么前一个值加以或者是后一个值减一就是断号的ID;如果前一个值等于后一个值,那么就是重号的ID
方法二:
也是存入到一维数组,不要想成二维数组的行,你就想输入多少次,一边输入一边判断最大最小值,再用一个桶子标记一下,谁被输入了,就放个小旗子进去。断号的标记数组肯定是0,重号的是1。标志数组的下标代表ID哈。然后再遍历,遍历的范围就是从最小到最大值,为什么?因为题目是ID号是随机的但是是连续的!!最后直接输出标志数组里面的元素是0和2的就好了
//方法一
#include <bits/stdc++.h>
using namespace std;
int main()
{
int N;
int nums[1000000];
cin >> N;
int a = 0, len = 0;
while(cin >> nums[a]){
a++;
len++;
}
int off = 0, re = 0;
sort(nums, nums+a);
for(int i = 0; i < a; i++){
if(nums[i+1] - nums[i] > 1){
off = nums[i] + 1;
}
if(nums[i+1]==nums[i]){
re = nums[i];
}
}
cout << off << " " << re;
return 0;
}
//方法二
#include <bits/stdc++.h>
using namespace std;
int main()
{
int flag[1000010] = {0};
int N = 0;
int a = 0, len = 0, max = -100001, min =100001;
int nums[1000001];
cin >> N;
while(N--){
while(cin >> a){
nums[len++] = a;
if(a > max){
max = a;
}
if(a < min){
min = a;
}
flag[a]++;
}
}
int off = 0, re = 0;
for(int i = min; i <= max; i++){
if(flag[i] == 0){
off = i;
}
if(flag[i] == 2){
re = i;
}
}
cout << off << " " << re;
return 0;
}
我知道了,我觉得是我不知道while(cin>>a){...}
当while(cin >> a)被执行时,它会首先尝试从输入流中读取一个值到a中,如果读取成功,循环条件为true,循环体内得代码块会被执行,然后,循环会再次检查cin >> a,尝试读取下一个值,如此往复。如果读取失败(比如用户没有输入任何内容就按下了EOF键,或者在读取整数时,输入了非数字字符),cin 的状态会变为fail,cin >> a的结果会转换为false,循环会终止。
这种结构在编写需要从输入中连续读取多个值的程序时非常有用,因为它能够自动处理输入结束的情况,并且可以在输入非法值时优雅地退出循环。
当cin进入fail状态后,需要清楚其错误状态并忽略掉导致错误的输入,否则后续的输入操作都会失败,这通常可以通过cin.clear()和cin.ignore()来实现
嗯!这个的确是简单
3!2!1!上代码
#include <iostream>
using namespace std;
int main()
{
int L, R;
cin >> L >> R;
int count = 0, a = 0;
for(int i = L; i <= R; i++){
a = i;
while(a != 0 ){
if(a % 10 == 2){
count++;
}
a /= 10;
}
}
cout << count;
return 0;
}
不断取数字判断就好:通过取模和除法实现
我觉得我就是太老实了,人家让我输入正整数我就蠢蠢的在那里int int 你放个string会怎么样啊
#include <bits/stdc++.h>
using namespace std;
int cmp(string a, string b){
return a+b > b+a;
}
int main()
{
int n ;
cin >> n;
string a[25];
for(int i = 0; i < n; i++){
cin >> a[i];
}
sort(a, a+n, cmp);
for(int i = 0; i < n; i++){
cout << a[i];
}
return 0;
}
这是字符串,而不是数字,所以a+b和b+a得到的是字符串而不是数值 +是字符串的连接不是数值的加法。
在C++中,字符串的比较是基于字典顺序的,这意味着字符串是从左到右逐字符比较的。
比如比较:
string a = "312";
string b = "213";
//比较a+b 和 b+a
string str1 = a+b; // "312213"
string str2 = b+a; // "213312"
- 首先比较第一个字符:'3'(来自a+b)和 '2'(来自b+a)。因为 '3' > '2',所以
a+b
在这一点上已经大于b+a
。- 由于已经确定了一个字符的比较结果,且该结果已经表明a+b大于b+a,所以没有必要继续比较后面的字符。