AcWing周赛67 哈希表

2022年9月6日 下午4:59 比赛总结 ,

这把..没有ak,第三题被卡了mapunordered_map,需要手写hash,前面两个题没什么好写的,直接写C吧..

比赛链接:AcWing周赛67

C.串联数字(哈希表)

题意
给定 n 个正整数 a1,a2,…,an

我们规定将正整数 aiaj 串联是指将 aj 直接接在 ai 后面构成一个新整数。

例如,1234 串联得到 12343412 串联得到 3412

现在,给定一个正整数 k,请你计算有多少个有序数对 (i,j)(i≠j) 满足,aiaj 串联得到的整数能够被 k 整除。

思路
对于当前的数,枚举10次,分别是往左边移动多少位,然后对$k$取余,进行计数。在这之前要先计算ans,思路不难,难得是优化常数

需要手写hash,但是我不是很强,还是看y总代码吧:

代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;
const int N = 200010, M = 10000007;

int n, m;
int a[N];
LL h[M];
int cnt[M];

int find(int r, int t)
{
    LL key = r * 100ll + t;
    int k = key % M;
    while (h[k] != -1 && h[k] != key)
        if ( ++ k == M)
            k = 0;
    if (h[k] == -1) h[k] = key, cnt[k] = 0;
    return k;
}

LL work()
{
    LL res = 0;
    memset(h, -1, sizeof h);
    for (int i = 0; i < n; i ++ )
    {
        int r = a[i] % m;
        if (r) r = m - r;
        int t = 0, x = a[i];
        while (x) t ++, x /= 10;
        res += cnt[find(r, t)];

        for (int j = 1, x = 10; j <= 10; j ++, x = x * 10ll % m)
            cnt[find((LL)a[i] * x % m, j)] ++ ;
    }
    return res;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);

    LL res = work();
    reverse(a, a + n);
    res += work();

    printf("%lld\n", res);

    return 0;
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注