Cx114514
2024-11-20 11:45:01
一道非常有思维含量的题目。
首先摒除无用操作:若
考虑每一个操作后的序列长什么样:
对于每个一次操作
前面一段是重复的,只需要令
接下来考虑多余的部分如何计算。
设
每次找到一个最大的
这样问题
证明如下:
若
若
据此结论,可保证每次递归次数为
每次递归都要二分查找一个最大的
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, Q, q[100005], s[100005], top, d[100005], f[100005];
void solve(int x, int y)
{
int t = upper_bound(s + 1, s + top + 1, x) - s - 1;
if (!t)
{
d[1] += y;
d[x + 1] -= y;
return;
}
f[t] += (x / s[t]) * y;
solve(x % s[t], y);
}
signed main()
{
cin >> n >> Q;
q[1] = n;
Q++;
for (int i = 2; i <= Q; i++)
cin >> q[i];
for (int i = 1; i <= Q; i++)
{
while (s[top] > q[i]) top--;
s[++top] = q[i];
}
f[top] = 1;
for (int i = top; i >= 2; i--)
{
solve(s[i] % s[i - 1], f[i]);
f[i - 1] += (s[i] / s[i - 1]) * f[i];
}
d[1] += f[1];
d[s[1] + 1] -= f[1];
for (int i = 1; i <= n; i++)
{
d[i] += d[i - 1];
cout << d[i] << endl;
}
return 0;
}