Official

D - Another Sigma Problem Editorial by nok0


\(f(x,y)\) を扱いやすい形に言い換えます。\(y\) を文字列として解釈したときの長さを \(\mathrm{len}(y)\) とすると、\(f(x,y) = 10^{\mathrm{len}(y)} x + y\) です。

\(i\) について、\(f(*,A_i)\) という形での \(A_i\) の寄与と \(f(A_i, *)\) という形での \(A_i\) の寄与を求めましょう。

前者は簡単です。\(f(*,A_i)\) では \(A_i\) はそのまま加算されるので、答えには \((i-1)A_i\) 寄与します。

後者を考えます。\(i < j\) かつ \(\mathrm{len}(A_j) = k\) なる \(j\) の個数を \(d_k\) とすると、寄与は \(\sum_{k=1}^{10} d_k 10^{k} A_i\) です。

\(d_k\) の更新は各 \(i\) について定数時間で行える(実装例も参考にしてください)ので、\(A\) の最大値を \(M\) とすれば 後者の寄与も各 \(i\) について \(\mathrm{O}(\log M)\) で計算できます。

以上より、答えを \(\mathrm{O}(N\log M)\) で求めることができました。

実装例(C++):

#include <bits/stdc++.h>
#include "atcoder/modint"

using namespace std;
using ll = long long;
using mint = atcoder::modint998244353;

int main() {
  int n;
  cin >> n;
  vector<int> a(n);
  for(auto &v : a) cin >> v;
  vector<int> d(11);
  for(int i = 0; i < n; i++) {
    d[to_string(a[i]).size()]++;
  }
  mint res = 0;
  vector<mint> p10(11, 1);
  for(int i = 1; i <= 10; i++) p10[i] = p10[i - 1] * 10;
  for(int i = 0; i < n; i++) {
    res += mint(a[i]) * i;
    d[to_string(a[i]).size()]--;
    for(int j = 1; j <= 10; j++) {
      res += p10[j] * a[i] * d[j];
    }
  }
  cout << res.val() << endl;
}

posted:
last update: