整数におけるGCDは,結合律を満たします.また,多くの言語でGCDの単位元は とされており,整数集合におけるGCDはモノイドであると言えます.従って,セグメント木を用いて,指定区間のGCDは, で高速に計算可能です.
また, とすると, を固定したとき, は について明らかに広義単調減少です.
従って,数列の区間における左端 を固定したとき, を満たす最大の を , を満たす最大の を として, 個が を満たします.
よって, 以上 以下の について上の値を二分探索とセグメント木を用いて で求めることができるため,全体の計算量は となりますが,セグメント木上で直接二分探索を行うことで,さらに計算量を に落とすことができます.
xxxxxxxxxx
using namespace std;
using namespace atcoder;
i64 e() { return 0; }
int main() {
i64 n, m;
cin >> n >> m;
vector<i64> a(n);
for (i64 &e: a) cin >> e;
segtree<i64, gcd, e> st(a);
auto f1 = [=](i64 x) {
if (x == 0) return true;
return x >= m;
};
auto f2 = [=](i64 x) {
if (x == 0) return true;
return x > m;
};
i64 ans = 0;
for(int i=0;i<n;i++) ans += st.max_right(i, f1) - st.max_right(i, f2);
cout << ans << endl;
}