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: