蓝桥杯训练赛(2)

目录

7-1 Excel地址

7-2 分巧克力

7-4 日期问题

7-9 k倍区间

7-10 正则问题


7-1 Excel地址

——第八届蓝桥省赛-C组 (60 分)

Excel 单元格的地址表示很有趣,它使用字母来表示列号。

比如,A 表示第 1 列,B 表示第 2 列,Z 表示第 26 列,AA 表示第 27 列,AB 表示第 28 列,BA 表示第 53 列 ....

当然 Excel 的最大列号是有限度的,所以转换起来不难。

如果我们想把这种表示法一般化,可以把很大的数字转换为很长的字母序列呢?

本题要求对输入的数字,输出其对应的 Excel 地址表示方式。

输入格式:

一个正整数。输入的整数范围 [1,2147483647]。

输出格式:

一个字母序列,表示输入数字对应的 Excel 地址表示方式。

输入样例:

2054

输出样例:

BZZ

思路L:进制转换,26进制,满26,不进,转化为z

题解代码如下:

#include <iostream>

using namespace std;

const int N = 1000;

int main()
{
    int n;
    cin >> n ;
    int a=n, b, i=0;
    char q[N];

    while( a>26 )
    {
        b = a%26;
        a /= 26;
        if(b==0)
        {
            a -= 1;
            b += 26;
            q[i++] = 'A' + b -1;
        }
        else q[i++] = 'A' + b -1;
    }
    q[i++] = 'A' + a -1;

    for(int j=i-1; j >= 0; j--) cout << q[j] ;

    return 0;
}

7-2 分巧克力

——第八届蓝桥省赛-AB组 (80 分)

儿童节那天有 K 位小朋友到小明家做客。

小明拿出了珍藏的巧克力招待小朋友们。

小明一共有 N 块巧克力,其中第 i 块是 Hi×Wi 的方格组成的长方形。

为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。

切出的巧克力需要满足:

  1. 形状是正方形,边长是整数
  2. 大小相同

例如一块 6×5 的巧克力可以切出 6 块 2×2 的巧克力或者 2 块 3×3 的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?

输入格式:

第一行包含两个整数 N 和 K。

以下 N 行每行包含两个整数 Hi 和 Wi。

输入保证每位小朋友至少能获得一块 1×1 的巧克力。 1≤ N,K ≤10^5 , 1≤ Hi, Wi≤ 10^5

输出格式:

输出切出的正方形巧克力最大可能的边长。

输入样例:

在这里给出一组输入。例如:

2 10
6 5
5 6

输出样例:

在这里给出相应的输出。例如:

2

思路:二分查找

题解代码如下:

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 1e5+10;

int n, k;
int res;
int h[N],w[N];

bool check(int x)
{
    int num=0;
    for( int i = 1; i <= n; i++ )
        num += (h[i]/x)*(w[i]/x);
    if(num>=k) return true;
    else return false;
}

int main()
{
    cin >> n >> k;
    for( int i = 1; i <= n; i++ )
        scanf("%d%d",&h[i],&w[i]);
    int l = 1, r = 1e5;
    while( l < r )
    {
        int mid = l + r + 1>> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
    res = l;
    cout << res << endl;

    return 0;
}

7-4 日期问题

——第八届蓝桥省赛-B组 (70 分)

小明正在整理一批历史文献。这些历史文献中出现了很多日期。

小明知道这些日期都在1960年1月1日至2059年12月31日。

令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。

更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。

比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。

给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?

输入格式:

一个日期,格式是”AA/BB/CC”。

即每个’/’隔开的部分由两个 0-9 之间的数字(不一定相同)组成。

0≤A,B,C≤9

输出格式:

输出若干个不相同的日期,每个日期一行,格式是”yyyy-MM-dd”。

多个日期按从早到晚排列。

输入样例:

02/03/04

输出样例:

2002-03-04
2004-02-03
2004-03-02

思路:枚举

代码如下:

#include <iostream>
#include <cstdio>

using namespace std;

int mon[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
int year,month,day;

bool isyear(int &year)
{
    if( year%400==0 || ( year%100!=0 && year%4==0 ) )
        return true;
    return false;
}

bool check_num(int &k )
{
    year = k/10000;
    month = (k%10000)/100;
    day = k%100;
    if( day < 1 || day > 31 )
        return false;
    if(month<1||month>12)
        return false;
    if( month!=2 )
    {
        if(day>mon[month])
            return false;
    }
    else
    {
        if(isyear(year))
        {
            if(day>mon[month]+1)
                return false;
        }
        else 
        {
            if(day>mon[month])
                return false;
        }
    }
    return true;
}


int main()
{
    int i = 19600101;
    int j = 20591231;
    int k, a, b, c;
    scanf("%d/%d/%d",&a,&b,&c);

    for( k = i; k <= j; k++)
    {
        if(check_num(k))
            if((year%100==a&&month==b&&day==c)||(month==a&&day==b&&year%100==c)||(day==a&&month==b&&year%100==c)||(month==a&&day==b&&year%100==c))
               printf("%d-%02d-%02d\n",year,month,day);
    }
    return 0;
}

7-9 k倍区间

——第八届蓝桥省赛-B组 (70 分)

给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K 倍区间。

你能求出数列中总共有多少个 K 倍区间吗?

输入格式:

第一行包含两个整数 N 和 K。

以下 N 行每行包含一个整数 Ai。

1≤N,K≤100000 , 1≤Ai≤100000

输出格式:

输出一个整数,代表 K 倍区间的数目。

输入样例:

5 2
1
2
3
4
5

输出样例:

在这里给出相应的输出。例如:

6

思路:前缀和哈希

代码如下:

#include <iostream>
#include <vector>
#include <cstdio>

using namespace std;

const int N = 100010;

long long s[N];
int res[N];
int a[N];
int n,k;

int main()
{
    long long cnt = 0;
    cin >> n >> k;

    for( int i = 1; i <= n; i++)
    {
        scanf("%d",&a[i]);
        s[i] = (s[i-1] + a[i])%k;
        
        //若前缀和相同,则区间和为零,则s[i]是K倍区间
        cnt += res[s[i]];
        res[s[i]]++;
    }

    cout << cnt + res[0] << endl ;

    return 0;
}

7-10 正则问题

——蓝桥第八届省赛-A组 (80 分)

考虑一种简单的正则表达式:

只由 x ( ) | 组成的正则表达式。

小明想求出这个正则表达式能接受的最长字符串的长度。

例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是6。

输入格式:

一个由x()|组成的正则表达式。输入长度不超过100,保证合法。

输出格式:

输出所给正则表达式能接受的最长字符串的长度。

输入样例:

在这里给出一组输入。例如:

((xx|xxx)x|(x|xx))xx 

输出样例:

在这里给出相应的输出。例如:

6

思路:暴力dfs

代码如下:

#include <iostream>
#include <vector>
#include <cstdio>

using namespace std;

int k;
int n;
string s;

int dfs()
{
    int res=0;
    while(k<s.size())
    {
        if(s[k]=='(')
        {
            k++;
            res += dfs();
            k++;
        }
        else if(s[k]==')')
        {
        //此处不可k++,应保持退出循环的状态,直到退出(的循环,k++
            break;
        }
        else if(s[k]=='|')
        {
            k++;
            res = max(res,dfs());
        }
        else k++,res++;
    }

    return res;
}
int main()
{
    cin >> s;

    n = dfs();
    cout << n;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AC自动寄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值