蓝桥杯每日一真题——[蓝桥杯 2020 省 A1] 整数小拼接(双指针+排序)

[蓝桥杯 2020 省 A1] 整数小拼接

题目描述

给定一个长度为 n n n 的数组 A 1 , A 2 , ⋯   , A n A_1,A_2,\cdots,A_n A1,A2,,An。你可以从中选出两个数 A i A_i Ai A j A_j Aj( i ≠ j i\neq j i=j),然后将 A i A_i Ai A j A_j Aj 一前一后拼成一个新的整数。例如 12345 可以拼成 1234534512。注意交换 A i A_i Ai A j A_j Aj 的顺序总是被视为 2 2 2 种拼法,即便是 A i = A j A_i=A_j Ai=Aj 时。

请你计算有多少种拼法满足拼出的整数小于等于 K K K

输入格式

第一行包含 2 2 2 个整数 n n n K K K

第二行包含 n n n 个整数 A 1 , A 2 , ⋯   , A n A_1,A_2,\cdots,A_n A1,A2,,An

输出格式

一个整数代表答案。

样例 #1

样例输入 #1

4 33
1 2 3 4

样例输出 #1

8

提示

对于 30 % 30\% 30% 的评测用例 1 ≤ n ≤ 1000 1\le n\le1000 1n1000 1 ≤ k ≤ 1 0 8 1\le k\le10^8 1k108 1 ≤ A i ≤ 1 0 4 1\le A_i\le10^4 1Ai104

对于所有评测用例, 1 ≤ n ≤ 1 0 5 1\le n\le10^5 1n105 1 ≤ k ≤ 1 0 10 1\le k\le10^{10} 1k1010 1 ≤ A i ≤ 1 0 9 1\le A_i\le10^9 1Ai109

蓝桥杯 2020 第一轮省赛 A 组 H 题。


思路:

1.找东西,怎么找优先考虑双指针。

暴力找,勉勉强强30分不甘心。

如果是一个有序的数组我们只要找到边界值就可以找到这个数组的符合条件的数。

要排序

cin >> n >> k;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    sort(a + 1, a + 1 + n);
    for (int i = 1; i <= n; i++)
        s[i] = to_string(a[i]);

这样就从小到大排好了。

2.l代表等待拼接的数r代表要和l拼接的数,r先拼在后面,只要我们找到当前位置能和l拼接的最大的r我们就找到了范围: r - l都是可以的。
如果是r的话会和下面r放在前面的时候的重复

3.找完当前位置的l我们就让l++找下一个位置的r,此时r不需要重置因为,r是在l小的时候不行的,l++后l位置上的数变大了。r如果重置回最大的话,或者保持原样的话一定不符合条件,所以我们可以让r–;

while (l <= r)
    {
        int t = cmp(s[r] + s[l], str); // r放前面l放后面
        if (t == 1)
        { // 同第一遍
            res += r - l;
            l++;
        }
        else if (t == 0)
        {
            res += r - l;
            l++, r--;
        }
        else
            r--;
    }

4.下面调换位置同理

全部代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
ll a[N];
string s[N], str; // s[i]表示转为字符串的 a[i];str表示转为字符串的 k
ll n, k;
int cmp(string s1, string s2)
{ // 字符串大小比较,不解释
    if (s1.size() == s2.size())
    {
        if (s1 == s2)
            return 0;
        else if (s1 < s2)
            return 1;
        else
            return -1;
    }
    if (s1.size() < s2.size())
        return 1;
    else
        return -1;
}
void init()
{ // 初始化,不解释
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    sort(a + 1, a + 1 + n);
    for (int i = 1; i <= n; i++)
        s[i] = to_string(a[i]);
    str = to_string(k);
}
int main()
{
    init();
    ll res = 0;
    // 第一遍双指针
    int l = 1, r = n;
    while (l <= r)
    {
        int t = cmp(s[l] + s[r], str);
        // l放前面,r放后面
        if (t == 1)
        { // 拼接后小于k
            res += r - l;
            l++;
        }
        else if (t == 0)
        { // 拼接后等于k
            res += r - l;
            l++, r--;
        }
        else
            r--; // 拼接后大于k
    }
    // 第二遍双指针
    l = 1, r = n;
    while (l <= r)
    {
        int t = cmp(s[r] + s[l], str); // r放前面l放后面
        if (t == 1)
        { // 同第一遍
            res += r - l;
            l++;
        }
        else if (t == 0)
        {
            res += r - l;
            l++, r--;
        }
        else
            r--;
    }
    cout << res;
    return 0;
}

小插曲:看题解的时候把l看成1了,made我直接看了2个小时这改改那改改样例对但是就是wa,最后结果是看错了,虽然颜色不一样,我太马虎了,真无语!!!。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

c0re

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

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

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

打赏作者

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

抵扣说明:

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

余额充值