野心
Journey
題意:
\(\text{range}(a, b, c)\) 表示序列
\[[a, a + c, a + 2c, \cdots, a + kc]
\]
其中 \(k\) 是滿足 \(a + kc < b\) 的最大非負整數。
給定大小為 \(n \le 2 \times 10^7\) 的陣列 \(g\),求
\[\sum_{a = 1}^n\sum_{b = a + 1}^n\sum_{c = 1}^n\sum_{i \in \text{range}(a, b, c)} g_i
\]
資料範圍暗示很明顯了,只放過線性做法。
每個 \(g_i\) 會被 \(a + kc = i\) 且 \(b > i\) 的三元組貢獻到。
設 \(f(i)\) 表示 \(a + kc = i\) 的 \((a, c)\) 對數
\[\begin{aligned}
f(i) &= \sum_{a = 1}^n\sum_{c = 1}^n[a + kc = i]\\
\\
&= n + \sum_{a = 1}^{i - 1}d(i - a)\\
\\
&= n + \sum_{a = 1}^{i - 1}d(i)\\
\end{aligned}
\]
因此只要把 \(d(i)\) 篩出來然後做一遍字首和即可。
最後再乘上 \(b\) 的 \(n - i + 1\) 種取值。
#include<bits/stdc++.h>
#define eb emplace_back
#define ep emplace
using namespace std;
using ll = long long;
constexpr int N = 2e7 + 5, P = 1e9 + 7;
int n; ll A, B, C, g[N];
ll d[N], s[N], iv[64];
int v[N], p[N], idx, c[N];
ll qpow(ll a, int b) {
ll c = 1;
while(b) {
if(b & 1) c = c * a % P;
b >>= 1;
a = a * a % P;
}
return c;
}
void init() {
for(int i = 1; i <= 60; ++ i) iv[i] = qpow(i, P - 2);
d[1] = 1;
for(int i = 2; i <= n; ++ i) {
if(!v[i]) {
c[i] = d[i] = 2;
p[++ idx] = i;
}
for(int j = 1, o; j <= idx && p[j] <= n / i; ++ j) {
o = i * p[j];
v[o] = 1;
if(i % p[j] == 0) {
d[o] = d[i] * iv[c[i]] % P * (c[i] + 1) % P;
c[o] = c[i] + 1;
break;
}
d[o] = d[i] * 2 % P;
c[o] = 2;
}
}
for(int i = 2; i <= n; ++ i) d[i] = (d[i] + d[i - 1]) % P;
}
inline int f(int i) {
return (n + d[i - 1]) % P;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n >> A >> B >> C, init();
cin >> g[n];
for(int i = n; i > 1; -- i) {
g[i - 1] = (A * g[i] % P * g[i] + B * g[i] + C) % P;
}
ll ans = 0;
for(int i = 1; i <= n; ++ i) {
ans = (ans + g[i] * f(i) % P * (n - i + 1)) % P;
}
cout << ans;
return 0;
}