[蓝桥杯 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 一前一后拼成一个新的整数。例如 12
和 345
可以拼成 12345
或 34512
。注意交换
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 1≤n≤1000, 1 ≤ k ≤ 1 0 8 1\le k\le10^8 1≤k≤108, 1 ≤ A i ≤ 1 0 4 1\le A_i\le10^4 1≤Ai≤104。
对于所有评测用例, 1 ≤ n ≤ 1 0 5 1\le n\le10^5 1≤n≤105, 1 ≤ k ≤ 1 0 10 1\le k\le10^{10} 1≤k≤1010, 1 ≤ A i ≤ 1 0 9 1\le A_i\le10^9 1≤Ai≤109。
蓝桥杯 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,最后结果是看错了,虽然颜色不一样,我太马虎了,真无语!!!。