[性质][AGC003E] Sequential operations on Sequence
可以观察到,对于 \(q_i\),若存在 \(j > i\) 使得 \(q_i \ge q_j\),那么操作 \(i\) 是可以忽略的,于是就转化为一个递增的 \(q\) 序列。
对于 \(q_i\),它的贡献可以看作两部分:
\(\bullet\) 重复了 \(q_i / q_{i-1}\) 次 \(q_{i-1}\),这个可以直接给 \(q_{i-1}\) 加上一个贡献系数;
\(\bullet\) \(q_i \bmod q_{i-1}\) 的部分。
第二点想二分一个 \(j\) 使得 \(q_{j} \le q_i \bmod q_{i-1} < q_{j+1}\),然后可以得到前面的 \(q_{j}\) 个数的贡献,减去之后继续递归下去,时间复杂度 \(\mathrm{O(n\log^2n)}\)。
但是当时并没有想清楚后面那个贡献怎么计算,绕的有点晕,思考无果后放弃了,点开题解发现正解就是这么做 /ll,还是太菜了/kk。
[\(\texttt{Code:}\)]
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
inline void read(int &x) {
x = 0; int f = 0; char c = getchar();
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
x = f ? -x : x;
}
const int cmd = 998244353;
const int N = 1e5 + 5;
int fpow(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = 1ll * a * a % cmd)
if (b & 1) res = 1ll * res * a % cmd;
return res;
}
int add(int a, int b) {a += b; return a < cmd ? a : a - cmd;}
int sub(int a, int b) {a -= b; return a < 0 ? a + cmd : a;}
int n, Q;
ll q[N], sum[N], mn, k[N];
vector<ll> opt;
void solve(ll rst, ll ck) {
if (rst <= opt[0]) {sum[rst] += ck; return;}
int pos = upper_bound(opt.begin(), opt.end(), rst) - opt.begin();
pos--;
k[pos] += rst / opt[pos] * ck;
solve(rst % opt[pos], ck);
}
int main() {
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
read(n); read(Q);
for (int i = 1; i <= Q; i++) scanf("%lld", &q[i]);
mn = 2e18;
for (int i = Q; i >= 1; i--)
if (q[i] < mn) {
mn = q[i];
opt.pb(q[i]);
}
if (n < mn) opt.pb(n);
int sz = opt.size();
reverse(opt.begin(), opt.end());
k[sz - 1] = 1;
for (int i = sz - 1; i; i--) {
k[i - 1] += opt[i] / opt[i - 1] * k[i];
solve(opt[i] % opt[i - 1], k[i]);
}
for (int i = opt[0] - 1; i >= 1; i--) sum[i] += sum[i + 1];
for (int i = 1; i <= opt[0]; i++) sum[i] += k[0];
for (int i = 1; i <= n; i++) printf("%lld\n", sum[i]);
return 0;
}

浙公网安备 33010602011771号