【题解】CF1029D Concatenated Multiples

版权声明:Powered By Fighter https://blog.csdn.net/qq_30115697/article/details/89320864

原题传送门

Solution

我们发现,题目中要求的"把a接到b前面"实际上等于 a 1 0 l o g 10 b + b a*10^{log_{10}b}+b 。于是我们自然想到预处理出 a i 1 0 x m o d    k a_i*10^x \mod k ,显然 x x 不会超过10。然后对于每个 a i a_i ,查询有多少数接到自己前面可以被 k k 整除。

预处理和枚举 a i a_i O ( n ) O(n) 复杂度是不可避免的,那么我们就考虑如何加快询问速度。

最容易想到的是,我们对于每个 x x ,把 a i x m o d    k a_i^{x}\mod k 插入到一个map​中。这样最多开10个map,并且每次查询只需 l o g 2 n log_2n 的时间,理论上可以通过此题。

然而到这一步的时候,我就看见同机房巨佬的 m a p map 被卡到了自闭,最后用了unordered_map才勉强卡过(话说unordered_map是不是需要c++11啊,哪位大佬科普一下)。然后才想起来 m a p map 有巨大的常数,于是我们想进一步优化。

我们发现,这里的 m a p map 实际上大材小用了,我们只需要简单的插入和查询,并不需要容器有序,于是我们可以自然的想到用unordered_map哈希表进行优化。虽然哈希表时间复杂度比较玄学,但再怎么样也不会比一只 l o g log 再加大常数的map慢。而且哈希表复杂度几乎可以看做常数级别。

所以我们就可以愉快地水掉一道紫题啦!!

Code

#include <bits/stdc++.h>
#define ll long long
#define MAX 200005
#define P 10007
using namespace std;

ll n, k;
ll a[MAX], p[20], lg[MAX];
struct hash_map {
    int head[MAX], Next[MAX], cnt;
    ll val[MAX], tot[MAX];
    
    hash_map(){
        cnt = 0;
        memset(head, 0, sizeof(head));
        memset(Next, 0, sizeof(Next));
        memset(val, 0, sizeof(val));
        memset(tot, 0, sizeof(tot));
    }
    
    void insert(ll x) {
        ll k = x%P;
        for(int i = head[k]; i; i = Next[i]) {
            if(val[i] == x) {
                tot[i]++;
                return;
            }
        }
        cnt++;
        Next[cnt] = head[k];
        head[k] = cnt;
        val[cnt] = x;
        tot[cnt] = 1;
    }

    ll find(ll x) {
        ll k = x%P;
        for(int i = head[k]; i; i = Next[i]) {
            if(val[i] == x) {
                return tot[i];
            }
        }
        return 0;
    }
}mp[15];

int main() {
    cin >> n >> k;
    p[0] = 1;
    for(int i = 1; i <= 10; i++) {
        p[i] = p[i-1]*10%k;
    }
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        ll tmp = a[i];
        while(tmp) {
            lg[i]++;
            tmp /= 10;
        }
    }
    for(int i = 1; i <= 10; i++){
        for(int j = 1; j <= n; j++){
            mp[i].insert(a[j]%k*p[i]%k);
        }
    }
    
    ll t, ans = 0;
    for(int i = 1; i <= n; i++){
        t = ((k-a[i])%k+k)%k;
        ans += mp[lg[i]].find(t);
        if((a[i]%k*p[lg[i]]%k+a[i]%k)%k == 0){
            ans--;
        }
    }
    cout << ans << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30115697/article/details/89320864