P3424 [POI2005]SUM-Fibonacci Sums
*P3424 [POI2005]SUM-Fibonacci Sums
POI 合集。
好题!先求和,再调整。
由于题目给出的
考虑从高往低位调整,即依次保证长为
我们发现最棘手的是
我们的目标是 尽可能消掉
不妨先执行进位操作,即
void flush(int p) {while(z[p] && z[p + 1]) z[p + 2]++, z[p]--, z[p + 1]--, p += 2;}
注意,当
执行完
啰里啰嗦这么一大堆,只是为了严谨证明以下做法的正确性:
- 从高到低考虑每一位
i 。保证i + 1 及其高位合法。 - 首先
\mathrm{flush}(i) 。 - 若
z_i \geq 2 ,则依次执行\mathrm{op}(i) ,\mathrm{flush}(i + 1) ,\mathrm{flush}(i) 。 - 此时
i 及其高位合法。
特殊情况:
时间复杂度分析:考虑 op 不改变 flush 的总复杂度均摊为
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, m, x[N];
void flush(int p) {while(x[p] && x[p + 1]) x[p + 2]++, x[p]--, x[p + 1]--, p += 2;}
int main() {
cin >> n; for(int i = 1; i <= n; i++) scanf("%d", &x[i]);
cin >> m; for(int i = 1, y; i <= m; i++) scanf("%d", &y), x[i] += y;
if(m > n) n = m;
for(int i = n; i; i--) {
flush(i);
if(x[i] >= 2) {
if(i >= 2) x[i] -= 2, x[max(1, i - 2)]++, x[i + 1]++;
else x[i + 1]++, x[i] -= 2;
flush(i + 1), flush(i);
}
} for(int i = n + 2; i; i--) if(x[i]) {cout << (n = i) << " "; break;}
for(int i = 1; i <= n; i++) putchar(x[i] + '0'), putchar(' ');
return 0;
}