现场编程大赛普及组初赛(题目+题解)2018-11-16

A(桶排序): 

/*年龄统计
朝宇妹这几天忙于统计科协所有会员的年龄,给你所有大于一周岁的人的年龄(单位:年),且已知没有人的年龄大于100岁,
请你将这些年龄升序排列
输入:
第一行是n——人数(0<n<=2000000)
第二行是n个人的年龄
输出:
输出n个分开的数字(年龄),升序排列。
样例输入:
5
2 3 2 3 1
样例输出:
1 2 2 3 3
例程:*/
#include <stdio.h>
#include <string.h>
const int N = 105;
int m[N], n;
 
int main() {
//freopen("F:\\现场编程大赛\\初赛\\普及组\\C\\in\\test0.in", "r", stdin);
	//freopen("F:\\现场编程大赛\\初赛\\普及组\\C\\out\\test0.out", "w", stdout);
	while (scanf("%d", &n)) {
		memset(m, 0, sizeof(m));
		int a, flag = 0;
		for (int i = 0; i < n; i++) {
			scanf("%d", &a);
			m[a]++;
		}
		for (int i = 1; i <= 100; i++)
			while (m[i]) {
				if (flag)
					printf(" %d", i);
				else {
					flag = 1;
					printf("%d", i);
				}
				m[i]--;
			}
		printf("\n");
	}
	return 0;
}

B(模拟): 

/*文件名
一橙小萌新这几天在整理文件,他觉得如果文件名有三个或以上的"x" (小写),这个文件的命名就不受欢迎,可以通过删除文件名中的x,使得文件名中不再 "xxx"这个字串,请求出最小的删除数目,有强迫症的他决定向机智的你求助。
例如:文件名为"exxxii",如果你删除第二个位置的字符,那么文件名变成"exxii",就会受欢迎了
输入:
第一行是n(3≤n≤100)——文件名的长度
第二行是文件名
输出:
输出最小的删除数目,如果本来文件名就很受欢迎,输出0
样例输入:
6
xxxiii
样例输出:
1
例程:*/
#include "iostream"
using namespace std;
const int Max=1e2+10;
char ch[Max];
int main()
{
    int n,ans=0;
    cin>>n>>ch;
    for(int i=0;i<n-2;i++){
        if(ch[i]=='x'&&ch[i+1]=='x'&&ch[i+2]=='x')
            ans++;
    }
    cout<<ans<<endl;
    return  0;
}

C(模拟): 

/*18岁生日
王潇洒大朋友n的18岁生日就要到了,他当然很开心,可是他突然想到一个问题,
是不是每个人从出生开始,到达18岁生日时所经过的天数都是一样的呢?
似乎并不全都是这样,所以他想请你帮忙计算一下他和他的几个朋友从出生到达18岁生日所经过的总天数,让他好来比较一下。
输入:
一个数T,后面T行每行有一个日期,格式是YYYY-MM-DD。如我的生日是1988-03-07。
输出:
T行,每行一个数,表示此人从出生到18岁生日所经过的天数。如果这个人没有18岁生日,就输出-1。
样例输入:
1
1988-03-07
样例输出:
6574
例程:*/
#include<iostream>//注意找规律,不要一天一天的模拟
#include<string>
using namespace std;
 
bool is_leap(int year){
	if((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){
		return true;
	}else{
		return false;
	}
}
 
int main(){
//freopen("F:\\现场编程大赛\\初赛\\普及组\\D\\in\\test0.in", "r", stdin);
	//freopen("F:\\现场编程大赛\\初赛\\普及组\\D\\out\\test0.out", "w", stdout);
	int m;
	cin>>m;
	string s;
	int year;
	int month;
	int day;
	int count;
	for(int i = 0; i < m; i++){
		cin>>s;
		year = (s[0] - 48) * 1000 + (s[1] - 48) * 100 + (s[2] - 48) * 10 + (s[3] - 48);
		month = (s[5] - 48) * 10 + (s[6] - 48);
		day = (s[8] - 48) * 10 + (s[9] - 48);
		if(is_leap(year) && month == 2 && day == 29){
			cout<<-1<<endl;
			continue;
		}
		count = 0;
		if(month <= 2){
			if(is_leap(year)){
				count++;
			}
		}
		year++;
		for(int j = 1; j <= 18; year++, j++){
			if(is_leap(year)){
				count++;
			}
		}
		year--;
		if(is_leap(year) && month <= 2){
			count--;
		}
		cout<<6570 + count<<endl;
	}
}

D(等差数列):

 /*总和问题
赵甜甜同学酷爱数学,有一天他看到书上有这样一个题目,给定序列1,2,3,...... N,你的任务是计算子序列之和为M的所有可能的子序列。他好像被难住了,只好向你求助。
输入:
第一行为N和M( 1 <= N, M <= 1000000000)
输出:
输出所有可能的子序列,格式见样例
样例输入:
50 30
样例输出:
[4,8]
[6,9]
[9,11]
[30,30]
例程:
/*这题主要要找到切入口(等差公式):假如有满足题意的情况:a+1,a+2,a+3,........a+n=m;即:(n*a)+n*(n+1)/2=m可以得到;n*n<2*m。
通过for循环,从1,2,3,........n,全部遍历一遍,查找满足条件的情况,即使得(n*a)+n*(n+1)/2=m成立(n,m已知,只需求出a,若a存在,则说明该种情况符合)

输出:[a+1,a+n].
*/*/
#include <iostream> 
#include <cmath>
#include <iomanip>
#include <string>
using namespace std;
int main(void)
{
//freopen("F:\\现场编程大赛\\初赛\\普及组\\E\\in\\test10.in", "r", stdin);
	//freopen("F:\\现场编程大赛\\初赛\\普及组\\E\\out\\test0.out", "w", stdout);
	int n,m;
	cin>>n>>m;
	
		for(int i=sqrt(2*m);i>=1;i--)
		{
			int a=(m-((i-1)*i)/2)/i;
			if(m==a*i+(i*(i-1))/2&&a>0)
            if(a>=1&&a+i-1<=n)
			    cout<<'['<<a<<','<<a+i-1<<']'<<endl;
		}
		cout<<endl;
	return 0;
}

E(并查集模板) :

/*多少桌子
今天是粥粥的生日。她邀请了很多朋友。现在是晚餐时间。粥粥想知道她至少需要多少桌子。
你必须知道并非所有的朋友都互相认识,而且所有的朋友都不想和陌生人呆在一起。这个问题的一个重要规则是,
如果我告诉你A知道B,B知道C,那意味着A,B,C彼此了解,所以他们可以留在一个桌子。
例如:如果我告诉你A知道B,B知道C,D知道E,所以A,B,C可以留在一个桌子,
D,E必须留在另一个桌子。所以粥粥至少需要2张桌子。
输入:
以两个整数N和M开始(1 <= N,M <= 1000)。N表示朋友的数量,朋友从1到N标记。然后M行数据。
每一行由两个整数A和B(A!= B)组成,这意味着朋友A和朋友B彼此了解
输出:
对于每个测试用例,只输出粥粥至少需要多少个表。
样例输入:
5 3
1 2
2 3
4 5
样例输出:
2
例程:*/
#include<cstdio>
#include<iostream>
using namespace std;
int fa[1005];
int n,m;
void init()
{
    for(int i=0;i<1005;i++)
        fa[i]=i;
}
int findd(int x)
{
    if(fa[x]!=x)
        fa[x]=findd(fa[x]);
    return fa[x];
}
void unionn(int x,int y)
{
    int a=findd(x),b=findd(y);
    if(a!=b)
         fa[b]=a;
    else return;
}
int main()
{
//freopen("F:\\现场编程大赛\\初赛\\普及组\\F\\in\\test0.in", "r", stdin);
	//freopen("F:\\现场编程大赛\\初赛\\普及组\\F\\out\\test0.out", "w", stdout);
	int n, m;
    
        int a,b,cnt=0;
        scanf("%d%d",&n,&m);
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            unionn(a,b);
        }
        for(int i=1;i<=n;i++)
        {
            findd(i);
            if(findd(i)==i)
                cnt++;
        }
        printf("%d\n",cnt);
   
    return 0;
}

F(字符串处理):

/*通配符匹配
qq学姐英语课闲来无事,看到了一个通配符的神奇定义。定义如下:你有两个字符串s和t,字符串s里面含有小写字母和最多一个'*',字符串t只含有小写字母。
s的长度是n,t的长度是m。
通配符'*'如果在s中可以用任意小写字母组成的字符串(可以是空串)替换之后,得到了t,
那么说明t和s是匹配的。
举个例子,若s= "aba*aba",那么以下字符串和它匹配:"abaaba", "abacaba" 和 "abazzzaba"
以下字符串就不匹配: "ababa", "abcaaba", "codeforces", "aba1aba", "aba?aba"
那么如果匹配就输出"YES",否则输出 "NO"
输入:
第一行是两个整数n和m(1≤n,m≤2*10^5) ——分别是字符串s的长度和字符串t的长度
第二行是字符串s
第三行是字符串t
输出:
如果可以从t可以得到s,就输出"YES"(没有引号),否则输出 "NO"(没有引号)
样例输入:
6 10
deco*s
decocesfor
样例输出:
NO
例程:*/
#include<stdio.h>
#include<string.h>
 
int main()
{
//freopen("F:\\现场编程大赛\\初赛\\普及组\\A\\in\\test0.in", "r", stdin);
	int n, m;
	while (~scanf("%d %d", &n, &m))
	{
		char s1[300005], s2[300005];
		scanf("%s", s1);
		getchar();
		scanf("%s", s2);
		if (n == m)//这里其实是最坑的,因为我只考虑了相等没有*,但是有的话如果其他的一样也是可以替换的,所以一开始直接判断一直被坑
		{
			
			for (int i = 0; i < n; i++)
			{
				if (s1[i] == '*')
				{
					s1[i] = s2[i];
					break;
				}
			}
			
			if (strcmp(s1, s2) == 0)
				printf("YES\n");
			else
				printf("NO\n");
		}
		else if (n > m + 1)
		{
			printf("NO\n");
		}
		else if (n == m + 1)
		{
			for (int i = 0; i < n; i++)
			{
				if (s1[i] == '*')
				{
					for (int j = i; j < n - 1; j++)
					{
						s1[j] = s1[j + 1];
					}
					s1[n - 1] = '\0';
					break;
				}
			}
			if (strcmp(s1, s2) == 0)
				printf("YES\n");
			else
				printf("NO\n");
		}
		else
		{
			int flag = 1;
			int i;
			for (i = 0; i < n; i++)
			{
				if (s1[i] == '*')
					break;
			}
			if (i == n)
				flag = 0;
			else
			{
				for (int k = 0; k < i; k++)
				{
					if (s2[k] != s1[k])
					{
						flag = 0;
						break;
					}
				}
				for (int k = i + 1; k <n; k++)
				{
					if (s2[m - (n - k)] != s1[k])
					{
						flag = 0;
						break;
					}
				}
 
			}
			if (flag)
				printf("YES\n");
			else
				printf("NO\n");
		}
	}
 
	return 0;
}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值