Official

D - 183183 Editorial by sounansya


\(i\)\(A_j\) の桁数 \(k\) を固定した時に条件を全て満たす \(j\) の個数を数えることを考えます。

\(A_j\) の桁数は \(k\) なので、 \(f(A_i,A_j)=10^{k}A_i+A_j\) と表すことができます。したがって、 \(f(A_i,A_j)\)\(M\) の倍数になることは \(A_j \equiv -10^{k}A_i \bmod M\) が成り立つことと同値です。

この条件を満たす \(j\) の個数は各 \(k\) に対し \(A_j\) の桁数が \(k\) となる \(j\) に対する \(A_j \bmod M\) の map を持つことで簡単に値を得ることができます。また、 map を用いずに \(A_j \bmod M\) を昇順に並べたリスト上で二分探索をすると(計算量は同じですが)より高速に計算することができます。

\(i\)\(O(N)\) 通り、\(k\)\(O(\log \max_i A_i)\) 通り存在し、 \(i,k\) を固定した後に条件を満たす \(j\) の個数を求めるのに \(O(\log N)\) 時間かかるので全体の計算量は \(O(N \log \max_i A_i \log N)\) となります。

以上を適切に実装することでこの問題に正答することができます。

実装例(Python3)

import bisect
import sys
input = sys.stdin.readline

n, m = map(int, input().split())
a = list(map(int, input().split()))
g = [[] for _ in range(11)]
for v in a:
    g[len(str(v))].append(v % m)
for gg in g:
    gg.sort()
ans = 0
for ai in a:
    for k in range(1, 11):
        ai = (ai * 10) % m
        key = (m - ai) % m
        ans += bisect.bisect_left(g[k], key + 1) - bisect.bisect_left(g[k], key)
print(ans)

実装例(C++)

#include <bits/stdc++.h>
using namespace std;
int main() {
	cin.tie(nullptr);
	ios::sync_with_stdio(false);
	int n;
	long long m;
	cin >> n >> m;
	vector<int> a(n);
	for (int &v : a)
		cin >> v;
	vector<vector<int>> g(11);
	for (int v : a)
		g[to_string(v).size()].push_back(v % m);
	for (auto &gg : g)
		sort(gg.begin(), gg.end());
	long long ans = 0;
	for (long long ai : a) {
		for (int k = 1; k < 11; k++) {
			ai *= 10, ai %= m;
			const int key = (m - ai) % m;
			ans += lower_bound(g[k].begin(), g[k].end(), key + 1) - lower_bound(g[k].begin(), g[k].end(), key);
		}
	}
	cout << ans << endl;
}

posted:
last update: