Official

F - Problem where +s Separate Digits Editorial by physics0523


\(|S|=1\) の場合、入力をそのまま出力すればよいです。
以下はそうでない場合を議論します。

今回の問題は、以下のように言い換えた方が見通しがよいです。

全てのありうる集合 \(A\) から一様ランダムにひとつ選んで \(T\) を作る際、 \(T\) を計算して得られる値の期待値の \(2^{|S|-1}\) 倍を求めよ。

ここで、「いくつかの式の値の総和」という足し合わせ方から、「 \(S\) の各文字が最終的な答えにどのくらい影響するか」という考えに切り替えます。(このように、値を足し合わせる時の着目の仕方を切り替えるテクニックは、「主客転倒」とも呼ばれます。)
では、 \(S\) の末尾から \(k\) 文字目について検討します。

  • それが \(1\) の位になる確率は \(\frac{1}{2}\)
  • それが \(10\) の位になる確率は \(\frac{1}{4}\)
  • それが \(100\) の位になる確率は \(\frac{1}{8}\)
  • \(\dots\)
  • それが \(10^{k-2}\) の位になる確率は \(\frac{1}{2^{k-1}}\)
  • それが \(10^{k-1}\) の位になる確率は \(\frac{1}{2^{k-1}}\)

一番下の文章だけが例外となることに注意してください。

\(S\) の右から \(k\) 文字目を \(x\) とおくと、この文字が最終的な答えを \(x \times (1 \times \frac{1}{2}+10 \times \frac{1}{4} + 100 \times \frac{1}{8} + \dots + 10^{k-2} \times \frac{1}{2^{k-1}} + 10^{k-1} \times \frac{1}{2^{k-1}})\) だけ増やすことになります。 この値は、等比数列の和に例外の項を調節したものに \(x\) を掛けたものとなります。これは、等比数列の和の公式で計算することも、下の位から計算を行って累積和のように計算することもできます。

計算量は \(O(N)\) となり、この問題を解くのに十分高速です。

実装例(C++)

#include<bits/stdc++.h>
#define mod 998244353

using namespace std;

long long power(long long a,long long b){
  long long x=1,y=a;
  while(b>0){
    if(b&1ll){
      x=(x*y)%mod;
    }
    y=(y*y)%mod;
    b>>=1;
  }
  return x%mod;
}

int main(){
  string s;
  cin >> s;
  if(s.size()==1){cout << s << '\n';return 0;}
  long long res=0,del=1,cur=0;
  for(int i=s.size()-1;i>=0;i--){
    cur+=del;cur%=mod;
    long long ce=(cur+del)%mod;
    res+=(s[i]-'0')*ce;res%=mod;
    del*=5;del%=mod;
  }
  res*=power(2,s.size()-2);res%=mod;
  cout << res << '\n';
  return 0;
}

Bonus! 出力が \(0\) となるケースをひとつ構成してください。

作り方 まず、「出力が \(0\) である」⇔「余りを取る前の答えが \(998244353\) の倍数である」であることに注意します。
ここで、本問題の解法を思い起こしてみましょう。この問題の答えは、「何らかの値」に \(2^{|S|-1}\) を掛けたものとなるはずです。なので、この「何らかの値」の部分を \(998244353\) の倍数にできないか考えます。
各桁ごとの答えへの貢献度を考えたときの、末尾から \(k\) 番目の文字の貢献度につく係数 \(C_k= (1 \times \frac{1}{2}+10 \times \frac{1}{4} + 100 \times \frac{1}{8} + \dots + 10^{k-2} \times \frac{1}{2^{k-1}} + 10^{k-1} \times \frac{1}{2^{k-1}})\)\(S\) の長さに依存しません。 また、 \(C\) の各項を \(2\) 倍した数列 \(C'\)\(C'=(2,11,56,281,1406,7031,35156,175781,878906,4394531,21972656,109863281,549316406,\dots)\) です。ここでの隣接項の比が約 \(5\) 倍であることを覚えておいてください。
ここで、先に \(S\) の長さを固定してしまうことを考え、 11...1 の場合の解を求めておきます。 すると、各桁ごとに、その桁を 2 から 9 までの別の数字に置き換えることができます。 ということは、 11...1 の場合の解と \(998244353\) との差を \(d\) とすると、 \(d = \sum B_iC_i\) となるような各要素が \(0\) 以上 \(8\) 以下であるような数列 \(B\) を求める問題へを書き換えることができます。 \(B\) の各項が \(0\) 以上 \(8\) 以下であるという条件なのに対し、 \(C'\) の隣接項の比が約 \(5\) 倍であり、先頭 \(2\) 項が \(2,11\) と来ていることから、貪欲法で得られた \(B\) からうまく調整できることが予想でき、この方法で実際に構成することも可能です。

posted:
last update: