SCU 4437 Carries(二分乱搞)题解
题意:问任意两对ai,aj相加的总进位数为多少。比如5,6,95分为(5,6)(5,95)(6,95),进位数 = 1 + 2 + 2 = 5
思路:显然暴力是会超时的。我们可以知道总进位数等于每一位进位数之和,所以我们可以把10个位数的进位分开算,每次%10^k,排序后用二分找到刚好的位置,然后算总数。
好像是唯一一次写二分一次A的题。
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<stdio.h> #include<string.h> #include<queue> #include<cmath> #include<map> #include<set> #include<vector> using namespace std; typedef long long ll; const int maxn = 1e5 + 10; const ll seed = 131; ll a[maxn], b[maxn], k; ll fac[15]; int mid(int l, int r, ll num){ int m, ans = r + 1; while(l <= r){ m = (l + r) >> 1; if(num + b[m] >= fac[k]) ans = m; if(num + b[m] < fac[k]) l = m + 1; else r = m - 1; } return ans; } int main(){ int n; fac[0] = 1; for(int i = 1; i <= 10; i++) fac[i] = fac[i - 1] * 10; while(~scanf("%d", &n)){ k = 0; ll ans = 0; for(int i = 1; i <= n; i++) scanf("%lld", &a[i]); for(int i = 1; i <= 10; i++){ k = i; for(int i = 1; i <= n; i++) b[i] = a[i] % fac[k]; sort(b + 1, b + n + 1); for(int i = 1; i <= n; i++){ int pos = mid(i + 1, n, b[i]); ans += (n - pos + 1); } } printf("%lld\n", ans); } return 0; }