2021_HUASACM_寒假周测_1 题解

我是比赛链接

A题(huas_sy):清除内奸
思路:

#include <iostream>
using namespace std;

int n, x;

int main(){
    
    
    cin >> n >> x;
    int y;
    for(int i = 0; i < n; i ++){
    
    		//	每个数只用一次,不需要开辟额外的空间存储
        cin >> y;
        if(x != y) cout << y << ' ';	//	不相等就输出
    }
    return 0;
}

B题(the_xin):棒球比赛
思路(the_xin):
比较D在是不是小于v*s或者大于vt

#include<iostream>
using namespace std;
int main(){
    
    
    int n,s,t,d;
    cin>>n>>s>>t>>d;
    int sd=n*s;
    int td=n*t;
    if(d<sd||d>td)puts("Yes");
    else puts("No");
    return 0;
}

帅气的咲夜~

C题(the_xin):坏了的键盘
思路1(the_xin):
从左往右遍历整个字符数组(从1开始),累计相同字符的和若其连续相同字符个数为奇数则当前字符键盘必不可能是坏的。

#include<bits/stdc++.h> 			// 万能头文件,包含绝大多数常用头文件
using namespace std;
string s;                           // C++提供的字符串变量
int cnt[30];
int main()
{
    
    
	cin >> s;
	int ans = 26;
	int len = 1;
	char ch = s[0];
	for(int i = 1; i < s.length(); i ++) {
    
    
		if(ch == s[i]) len ++;
		else {
    
    
			if(len % 2 == 1 && !cnt[ch - 'a']) {
    
    
				ans --;
				cnt[ch - 'a'] = 1;
			}
			len = 1;
			ch = s[i];
		}
	}
	if(len % 2 == 1 && !cnt[ch - 'a']) ans --;
	cout << ans;
	return 0;
}

思路2(huas_sy):
从左至右遍历(从1开始),将每一位分成和前面字符相同与不相同去谈论,若相同则累加,否则判断累计和是否为奇数,奇数则说明当前字符必定为好的,在a数组中标记。最后求a中有多少个没被标记的数。

#include <iostream>
using namespace std;

int n, a[30];						// 全局变量定义后系统自动初始化其为0
string s;                           // C++提供的字符串变量

int main(){
    
    
    cin >> s;
    n = s.length();
    int ans = 0, sum = 1, x = s[0] - 'a';
    for(int i = 1; i < n; i ++){
    
    
        if(s[i] == s[i-1]){
    
    
            sum ++;
        }else {
    
    
            if(sum & 1) a[x] = 1;	// ‘&’ 运算符为位运算符的一种,自行百度其用法,不懂可群里沟通
            sum = 1;
        }
        x = s[i] - 'a';
    }
    if(sum & 1) a[x] = 1;
    for(int i = 0; i < 26; i ++)
        if(a[i] == 0) ans ++;
    cout << ans;
    return 0;
}

再来一个~

D题(huas_sy):干掉小团体
思路(huas_sy):
发现对于每个人的爱好值,其范围是比较小的,完全可以开辟一个数组令其下标范围大于爱好值的取值范围,然后将爱好值对号入座(类似于“桶排序”的思路),最后将无爱好值相同的爱好值顺序打印输出即可。

#include <iostream>

using namespace std;

int n, a[200009], b[200009];
 
int main(){
    
    
    cin >> n;
    int x;
    for(int i = 0; i < n; i ++){
    
    
        cin >> a[i];
        b[a[i]] ++;
    }
    for(int i = 0; i < n; i ++){
    
    
        if(b[a[i]] < 2) cout << a[i] << ' ';
    }
    return 0;
}

E题(the_xin):简单的数组
思路(huas_sy):
分别维护前缀最大值和前缀最小值最后答案即为最大值和最小值的差(想想前缀和差值的意义)

#include <iostream>

using namespace std;

int n;
 
int main(){
    
    
    cin >> n;
    int a, b, x, sum = 0;
    a = b = 0;     			  // 初始化最值为0
    for(int i = 0; i < n; i ++){
    
    
        cin >> x;
        sum += x;
        if(sum < a) a = sum;
        if(sum > b) b = sum;
    }
    cout << b - a;
    return 0;
}

嘿嘿~

F题(huas_sy):排位次
思路1(the_xin):
Node结构体中x存的是运动员得分 id表示是第几个运动员
对nodes利用x进行排序后 id为原来询问的顺序
这时候nodes数组存放的是按照得分排序后的结果
数组下标就是他的排名 node[i].id存放第几个运动员在i名
我们可以用数组b来表示 其中第i个元素表示第i个运动员的排名
我们只需要遍历nodes数组 使得b[node[i].id]=i
最后按顺序输出即可

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int N=2e5+10;
struct Node{
    
    
    int x,id;
    bool operator<(const Node &a )const {
    
               // C++提供的运算符重载,其关键字为: operator     
        return x>a.x;                               // 重载比较运算符之后 Node 之间的比较仅与 x 字段有关,配合后文的 sort 函数使用           
    }
}nodes[N];
int b[N];
int main()
{
    
    
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
    
    
        scanf("%d",&nodes[i].x);                    // x 存储运动员得分
        nodes[i].id=i;                              // id 存储运动员的位置
    }
    sort(nodes+1,nodes+1+n);                        // 由 <algorithm> 头文件提供的一个排序函数 sort
    for(int i=1;i<=n;i++){
    
    
        b[nodes[i].id]=i;                           // 第 nodes[i].id 个运动员的名次是 i
    }
    for(int i=1;i<=n;i++)
        printf("%d ",b[i]);
    return 0;
}

思路2(huas_sy):
将 b 数组初值赋值为 a 数组的下标(绑定)
利用 a 数组的值对 b 数组进行递减排序(排序方法:归并排序;利用 c 数组进行过渡;时间复杂度为O(nlogn) )
通过排序后的 b 数组还原 a 数组中各个位置的名次(此时 b 数组的下标为名次,b 数组的值为该名次运动员被询问的次序)(溯源)

#include <iostream>
 
using namespace std;
 
int n, a[200009], b[200009], c[200009];
 
void fu1(int l, int r, int m){
    
    					// 合并有序区间 [l, r-1] , [r, m]
    int i, j, coun = 0;
    for(i = l, j = r; i < r && j <= m; ){
    
    
        if(a[b[i]] > a[b[j]]){
    
    					// 比较时根据下标绑定的 a 进行比较
            c[coun ++] = b[i];
            i ++;
        }else {
    
    
            c[coun ++] = b[j];
            j ++;
        }
    }
    while(i != r){
    
    
        c[coun ++] = b[i ++];
    }
    while(j != m + 1){
    
    
        c[coun ++] = b[j ++];
    }
    for(i = l, j = 0; j < coun; j ++, i ++){
    
    	// 将排序好的数组赋值回 b 数组
        b[i] = c[j];
    }
}
void fu(int l, int r){
    
    							// 对区间 l, r 排序
    if(l == r) return;
    int mid = (l + r) / 2;						// 二分中点
    fu(l, mid);
    fu(mid + 1, r);
    fu1(l, mid + 1, r);							// 对排序后的两个区间,进行有序合并
}
int main(){
    
    
    cin >> n;
    int x;
    for(int i = 0; i < n; i ++){
    
    				// 初始化 a,b 数组
        cin >> a[i];
        b[i] = i;
    }
    fu(0, n - 1);								// 对 b 数组 0 到 n-1 的位置进行排序
    for(int i = 0; i < n; i ++){
    
    				// 溯源
        a[b[i]] = i;
    }
    for(int i = 0; i < n; i ++)
        cout << a[i] + 1 << ' ';
    return 0;
}

感谢观看
对于后续的题目希望大家再接再厉,我们的水平是有限的,若有错误随时联系我们改正。
关于题目和解题思路,均已用小括号标识了提供者;一些初次提到的点也已做注释说明,以后将不再赘述。
最后:网络是个好东西,它庞大的容量足以你在里面找到绝大多数知识,智者会利用它,愚人也会利用它,只是用它做的事情有所不同而已。
哈哈,同道中人【握手】

猜你喜欢

转载自blog.csdn.net/weixin_46216585/article/details/113758893