蓝桥杯备赛练习2

本文讨论了如何计算给定8位数日期之后的下一个回文日期和ABABBABA型回文日期,涉及编程技巧和日期逻辑。文章提供了一个C++程序示例来解决这个问题。
摘要由CSDN通过智能技术生成

[蓝桥杯 2020 省 AB2] 回文日期

题目描述

2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按 yyyymmdd 的格式写成一个 8 8 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。

有人表示 20200202 是“千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。

也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA 型的回文日期。对此小明也不认同,因为大约 100 100 100 年后就能遇到下一个 ABABBABA 型的回文日期:21211212 即 2121 年12 月12 日。算不上“千年一遇”,顶多算“千年两遇”。

给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个 ABABBABA 型的回文日期各是哪一天。

输入格式

输入包含一个八位整数 N N N,表示日期。

输出格式

输出两行,每行 1 1 1 个八位数。第一行表示下一个回文日期,第二行表示下
一个 ABABBABA 型的回文日期。

样例 #1

样例输入 #1

20200202

样例输出 #1

20211202
21211212

提示

对于所有评测用例, 10000101 ≤ N ≤ 92200229 10000101 \le N \le 92200229 10000101N92200229,保证 N N N 是一个合法日期的 8 8 8 位数表示。

蓝桥杯 2020 第二轮省赛 A 组 G 题(B 组 G 题)。

思路:其实没啥思路,就是考验代码实现的基本功

AC Code

#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define int long long
#define pii pair<int, int>
#define pb push_back
#define gcd __gcd
#define lcm(a, b) (a * b) / gcd(a, b)
#define all(a) a.begin(), a.end()
#define mem(a, x) memset(a, x, sizeof(a))
#define f(i, s, e) for (int i = s; i <= e; i++)
#define ff(i, s, e) for (int i = s; i >= e; i--)
#define setbits(x) __builtin_popcount(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 100000007
#define maxn (ll)(2e5 + 5000)
#define INF 0x3f3f3f3f
using namespace std;
// set<int>::iterator it;
// 判断是否是月份
bool ismonth(int x)
{
    return x >= 1 && x <= 12;
}
// 判断是否是闰年
bool isleap(int x)
{
    return x % 400 == 0 || (x % 4 == 0 && x % 100 != 0);
}
// 判断是否是合法日期
bool isdate(int y, int m, int d)
{
    if (m == 2)
    {
        if (isleap(y))
        {
            return d >= 1 && d <= 29;
        }
        else
        {
            return d >= 1 && d <= 28;
        }
    }
    else if (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12)
    {
        return d >= 1 && d <= 31;
    }
    else
    {
        return d >= 1 && d <= 30;
    }
}
// 检查是否是回文数
bool ishuiwen(string s)
{
    int n = s.size();
    for (int i = 0; i < n / 2; i++)
    {
        if (s[i] != s[n - i - 1])
        {
            return false;
        }
    }
    return true;
}
// 判断ABABBABA
bool isABABBABA(string s)
{
    if (ishuiwen(s))
    { // 首先它得是个回文数
        // 接下来只需判断前4位是否合法
        if (s[0] != s[2] || s[1] != s[3] || s[0] == s[1])
            return false;
        // 结合ABABBABA思考
        return true;
    }
    return false;
}
signed main(void)
{
    ios::sync_with_stdio(false), cin.tie(nullptr);
    string s;
    int n;
    cin >> n;
    int flag1 = 0;
    f(i, n + 1, 99999999)
    {
        s = to_string(i);
        int date = i;
        int year = date / 10000;
        int month = date % 10000 / 100;
        int day = date % 100; // 分离年月日
        // 检查是否合法
        if (!ismonth(month) || !isdate(year, month, day))
        {
            continue;
        }
        if (ishuiwen(s) && !flag1)
        {
            cout << i << endl;
            flag1 = 1;
        }
        if (isABABBABA(s) && flag1)
        {
            cout << i << endl;
            return 0;
        }
    }
    return 0;
}

[HNOI2004] 打鼹鼠

题目描述

鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢把头探出到地面上来透透气的。根据这个特点阿牛编写了一个打鼹鼠的游戏:在一个 n × n n \times n n×n 的网格中,在某些时刻鼹鼠会在某一个网格探出头来透透气。你可以控制一个机器人来打鼹鼠,如果 i i i 时刻鼹鼠在某个网格中出现,而机器人也处于同一网格的话,那么这个鼹鼠就会被机器人打死。而机器人每一时刻只能够移动一格或停留在原地不动。机器人的移动是指从当前所处的网格移向相邻的网格,即从坐标为 ( i , j ) (i, j) (i,j) 的网格移向 ( i − 1 , j ) , ( i + 1 , j ) , ( i , j − 1 ) , ( i , j + 1 ) (i-1, j), (i+1, j), (i, j-1), (i, j+1) (i1,j),(i+1,j),(i,j1),(i,j+1) 四个网格,机器人不能走出整个 n × n n \times n n×n 的网格。游戏开始时,你可以自由选定机器人的初始位置。

现在知道在一段时间内,鼹鼠出现的时间和地点,请编写一个程序使机器人在这一段时间内打死尽可能多的鼹鼠。

输入格式

第一行为 n , m n, m n,m n ≤ 1000 n \le 1000 n1000 m ≤ 10 4 m \le {10}^4 m104),其中 m m m 表示在这一段时间内出现的鼹鼠的个数,接下来的 m m m 行中每行有三个数据 t i m e , x , y \mathit{time}, x, y time,x,y 表示在游戏开始后 t i m e \mathit{time} time 个时刻,在第 x x x 行第 y y y 个网格里出现了一只鼹鼠。 t i m e \mathit{time} time 按递增的顺序给出。注意同一时刻可能出现多只鼹鼠,但同一时刻同一地点只可能出现一只鼹鼠。

输出格式

仅包含一个正整数,表示被打死鼹鼠的最大数目。

样例 #1

样例输入 #1

2 2	         
1 1 1		
2 2 2

样例输出 #1

1

思路:我们可以考察作为终点的结果,即设dp[i]是以i为终点的最大数量

AC Code

#include <bits/stdc++.h>
#include <stack>
#define ll long long
#define int long long
#define pii pair<int, int>
#define pb push_back
#define gcd __gcd
#define lcm(a, b) (a * b) / gcd(a, b)
#define all(a) a.begin(), a.end()
#define mem(a, x) memset(a, x, sizeof(a))
#define f(i, s, e) for (int i = s; i <= e; i++)
#define ff(i, s, e) for (int i = s; i >= e; i--)
#define setbits(x) __builtin_popcount(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 100000007
#define maxn (ll)(2e5 + 5000)
#define INF 0x3f3f3f3f
using namespace std;
// set<int>::iterator it;
int n, m;
struct node
{
    int time;
    int x;
    int y;
};
struct node a[maxn];
int dp[maxn] = {0};//dp[i]表示以第i个时刻为终点打到的最多老鼠数
// 计算哈曼顿距离
int ham(int x1, int y1, int x2, int y2)
{
    return abs(x1 - x2) + abs(y1 - y2);
}
signed main(void)
{
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cin >> n >> m;
    f(i, 1, m)
    {
        cin >> a[i].time >> a[i].x >> a[i].y;
        dp[i]=1;//初始化,保证每次至少都能打到一个
    }
    f(i, 1, m)
    {
        f(j, 1, i - 1)
        {
            if (ham(a[i].x, a[i].y, a[j].x, a[j].y) <= a[i].time - a[j].time)
            {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
    }
    int ans = 0;
    f(i, 1, m)
    {
        ans = max(ans, dp[i]);
    }
    cout << ans << endl;
    return 0;
}

快速求和

题目背景

2023-10-08 update: 新增两组 hack。

2023-12-16 update: 新增两组 hack。

题目描述

给定一个数字字符串,用最小次数的加法让字符串等于一个给定的目标数字。每次加法就是在字符串的某个位置插入一个加号。在里面要的所有加号都插入后,就像做普通加法那样来求值。

例如,考虑字符串12,做 0 0 0 次加法,我们得到数字 12 12 12。如果插入 1 1 1 个加号,我们得到 3 3 3,因此,这个例子中,最少用 1 1 1 次加法就得到数字 3 3 3

再举一例,考虑字符串303和目标数字 6 6 6,最佳方法不是3+0+3。而是3+03。能这样做是因为一个数的前导 0 0 0 不会改变它的大小。

输入格式

第一行:一个字符串 s s s

第二行:一个整数 n n n

输出格式

一行一个整数表示最少的加法次数让 s s s 等于 n n n。如果怎么做都不能让 s s s 等于 n n n ,则输出 − 1 -1 1

样例 #1

样例输入 #1

99999
45

样例输出 #1

4

提示

数据规模与约定

对于 100 % 100\% 100% 的数据,保证 1 ≤ len ⁡ ( s ) ≤ 40 1\le \operatorname{len}(s)\le40 1len(s)40 1 ≤ n ≤ 1 0 5 1 \leq n\le10^5 1n105

思路:这是动态规划题单里的,但是一开始觉得,记忆化dfs也行,但是他就是卡着几个测试点过不了,没办法,后面改用了迭代加深搜索,枚举答案,还加了卡时,真的心疲力尽

AC Code

#include <bits/stdc++.h>
#define ll long long
#define int long long
#define pii pair<int, int>
#define pb push_back
#define gcd __gcd
#define lcm(a, b) (a * b) / gcd(a, b)
#define all(a) a.begin(), a.end()
#define mem(a, x) memset(a, x, sizeof(a))
#define f(i, s, e) for (int i = s; i <= e; i++)
#define ff(i, s, e) for (int i = s; i >= e; i--)
#define setbits(x) __builtin_popcount(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 100000007
#define maxn (ll)(2e5 + 5000)
#define INF 0x3f3f3f3f
using namespace std;
// set<int>::iterator it;
char s[100];
int n;
int len;
int ans;
void dfs(int deep, int cnt, int x1, int la)
{
    if ((double)clock() / CLOCKS_PER_SEC > 0.9)
    {
        cout << -1;
        exit(0);
    }
    if (x1 > n)
    {
        return;
    }
    if (deep == len + 1)
    {
        if (x1 == n)
        {
            cout << ans << endl;
            exit(0);
        }
        return;
    }
    if (cnt > 0)
    {
        dfs(deep + 1, cnt - 1, x1 + s[deep] - '0', s[deep] - '0');
    }
    dfs(deep + 1, cnt, x1 - la + la * 10 + s[deep] - '0', la * 10 + s[deep] - '0');
    return;
}
signed main()
{
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cin >> (s + 1) >> n;
    len = strlen(s + 1);
    for (ans = 0; ans < len; ans++)
    {
        dfs(1, ans, 0, 0);
    }
    cout << -1;

    return 0;
}

80 分的Code(如果你知道怎么改进,请教教我,蟹蟹尼)

#include <algorithm>
#include <bits/stdc++.h>
#define ll long long
#define int long long
#define pii pair<int, int>
#define pb push_back
#define gcd __gcd
#define lcm(a, b) (a * b) / gcd(a, b)
#define all(a) a.begin(), a.end()
#define mem(a, x) memset(a, x, sizeof(a))
#define f(i, s, e) for (int i = s; i <= e; i++)
#define ff(i, s, e) for (int i = s; i >= e; i--)
#define setbits(x) __builtin_popcount(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 100000007
#define maxn (ll)(2e5 + 5000)
#define INF 0x3f3f3f3f
using namespace std;
// set<int>::iterator it;
string s;
int len;
int n;
bool vis[1005] = {false};
int ans = INF;
int dp[maxn][50];
void dfs(int x1, int deep, int cnt, int la)
{
    if ((double)clock() / CLOCKS_PER_SEC > 0.9)
    {
        cout << -1;
        exit(0);
    }
    if (x1 > n || cnt >= ans) // 剪枝条件
    {
        return;
    }
    if (dp[x1][deep] != -1 && dp[x1][deep] <= cnt) // 如果已经计算过并且结果更优,直接返回
    {
        return;
    }
    dp[x1][deep] = cnt; // 更新记忆化数组
    if (deep == len)
    {
        if (x1 == n)
        {
            ans = min(ans, cnt);
        }
        return;
    }
    f(i, 0, len - 1)
    {
        if (vis[i])
        {
            continue;
        }
        vis[i] = true;
        if (cnt < len)
        {
            dfs(x1 + s[i] - '0', deep + 1, cnt + 1, s[i] - '0');
        }
        dfs(x1 - la + la * 10 + s[i] - '0', deep + 1, cnt, la * 10 + s[i] - '0');
        vis[i] = false;
    }
    return;
}
signed main(void)
{
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cin >> s;
    cin >> n;
    len = s.size();
    mem(dp, -1); // 初始化记忆化数组
    dfs(0, 0, 0, 0);
    if (ans == INF)
    {
        ans = -1;
    }
    cout << ans << endl;
    return 0;
}

[蓝桥杯 2021 省 B] 杨辉三角形

题目描述

下面的图形是著名的杨辉三角形:

如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:

1 , 1 , 1 , 1 , 2 , 1 , 1 , 3 , 3 , 1 , 1 , 4 , 6 , 4 , 1 , … 1,1,1,1,2,1,1,3,3,1,1,4,6,4,1, \ldots 1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,

给定一个正整数 N N N,请你输出数列中第一次出现 N N N 是在第几个数。

输入格式

输入一个整数 N N N

输出格式

输出一个整数代表答案。

样例 #1

样例输入 #1

6

样例输出 #1

13

提示

对于 20 % 20 \% 20% 的评测用例, 1 ≤ N ≤ 10 1 \leq N \leq 10 1N10;

对于所有评测用例, 1 ≤ N ≤ 1 0 9 1 \leq N \leq 10^9 1N109

蓝桥杯 2021 第一轮省赛 B 组 H 题。

思路:大概的估计一下,对角线行数K是20左右,然后二分枚举就行了,每一行对角线都是单调不降的,若一个斜行开头的数比 n 大,则答案一定不在该斜行中。

AC Code

#include <bits/stdc++.h>
#define ll long long
#define int long long
#define pii pair<int, int>
#define pb push_back
#define gcd __gcd
#define lcm(a, b) (a * b) / gcd(a, b)
#define all(a) a.begin(), a.end()
#define mem(a, x) memset(a, x, sizeof(a))
#define f(i, s, e) for (int i = s; i <= e; i++)
#define ff(i, s, e) for (int i = s; i >= e; i--)
#define setbits(x) __builtin_popcount(x)
#define zrobits(x) __builtin_ctzll(x)
#define mod 100000007
#define maxn (ll)(2e5 + 5000)
#define INF 0x3f3f3f3f
using namespace std;
// set<int>::iterator it;
// 计算组合数
int N;
ll C(ll n, ll m)
{
    if (m > n - m)
    {
        m = n - m;
    }
    ll ans = 1;
    for (ll i = 1; i <= m; i++)
    {
        ans = ans * (n - i + 1) / i;
    }
    return ans;
}
signed main(void)
{
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cin >> N;
    if (N == 1)
    {
        cout << 1 << endl;
        return 0;
    }
    ff(i, 20, 0)
    {
        int l = 2 * i;
        int r = 1e9;
        int mid, lim;
        while (l <= r)
        {
            mid = (l + r) >> 1;
            lim = C(mid, i);
            if (lim == N)
            {
                cout << (mid + 1) * mid / 2 + i + 1 << endl;
                return 0;
            }
            else if (lim > N)
            {
                r = mid - 1;
            }
            else
            {
                l = mid + 1;
            }
        }
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值