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;
}

 

posted @ 2018-11-03 13:27  KirinSB  阅读(186)  评论(0编辑  收藏  举报