蓝桥杯 整数小拼接
题意
给定数组 , 求其中两两组合产生数字$ \le k$的个数
思路
先排序 , 再双指针 , \(i\)指向左边 , \(j\)指向右边
当\((i,j)\)配对符合时 , \(ans\) 加上 \(j-i\) , 如果此时\(check(i,i)\)满足 , 说明被算了两次 , 那么\(ans--\) , 然后\(i\)右移
当\((i,j)\)配对不符合时 , \(j\)移动直到为\(j=0\)或者 \(check(i,j)\)满足 , 然后同上
几个疑问:
Q : 排序怎么可以不用字典序?
首先 , 只有当位数不同时才可能出现字典序和数值序不同的情况 , 比如 \(9\)和\(90\) , 且数值型排序结果必然是低位数在前 , 高位数在后
而在这种情况下 , 对一个确定的 \(a_j\) , 如果低位数的数拼凑\(a_j\)已经超出了预定值 , 那么高位数的拼凑后必然也超出预定值
对一个确定的 \(a_i\) , 从高位数的\(a_j\)向低位数的\(a_j\)测试是满足单调的
因此 , 该题可以用字典序 , 也可以数值排序
Q : 为什么终止条件为\(i \le n\) 而不是 \(i \le j\)?
当\(i\)达到某个临界值时 , \(j\)会迅速下降 , 此时\(j\)可能小于\(i\) , 但是仍然应该计数
而当\(i\)跨过临界值时 , \(j\)不一定已经下降到\(0\)(因为位数可能有很多)
只有当\(j\)为\(0\)时才是真的无数可走 , 所以可以把循环条件改为\(i<=n && j\)
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long int
inline int read() {
int res= 0,f =1;
char ch = getchar();
while (ch<'0' || ch > '9') {
if (ch=='-')f=-1;
ch = getchar();
}
while (ch>='0' && ch <='9') {
res = res * 10 + ch-'0';
ch = getchar();
}
return res * f;
}
const int N = 1e5+10;
int a[N];
int k;
bool cmp(const string& a,const string& b) {
string ab = a + b;
string ba = b + a;
return ab <ba;
}
bool check(int x,int y) {
return stoll((to_string(a[x]) + to_string(a[y]))) <= k;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n = read();
k = read();
for (int i =1; i<= n; i++) {
a[i] =read();
}
sort(a+1,a+1+n);
int ans = 0;
for (int i =1,j=n; i<=n; i++) {
while (j>0&&!check(i,j))j--;
ans += j;
if (j>=i)
ans--;
}
cout<<ans<<"\n";
return 0;
}

浙公网安备 33010602011771号