週間前のブログが、捨てられた治療の側面を超える指導、そして今日は、彼らが再び祝います。
問題の説明
長さが与えられた\(N- \)は列の数である(\ {a_iを\} \)\、シークA最短線形再帰シーケンス(\ \ {B_i \} \) (設定長さ\(M \)すべてのために)、そのような\(M \のLeq K \ n型のLeq \)がある\(a_k = \ sum_ {iは b_i \) - = 0} ^ M A_ {I kは}
複雑さの要件:\(O(^ N-2)\)
外観は非常に線形再帰消費の定数係数に合います。
アルゴリズムのプロセス
インクリメンタル建設。
我々は現在の計算されたと仮定- (\ A_ {1。0 ... Iを})\線形回帰シーケンス演算処理を、我々が持っていた得た。(C \)\、漸化式を\(I \)で再帰式\(fail_i \)初めて無効ための位置。
始まり\(C = 0 \) 、私たちは、空の再帰を持っています。
今、私たちは数追加\(a_iをを\) 。
セット\(R_C \)の長さ(\ M)\、\(= a_iをdelta_i - \ sum_ K = {} 1 A_ ^ {M} I { - } R_C K(K)\)
もし\(delta_i = 0 \) 、\(R_C \)はまだ正当な再帰的です。
そうでなければ、我々はしたい\(R_C \)新しい再帰的な資格を取得するために調整を行うこと。
もし\(C = 0 \) 、最初\(I - 1 \)の数である(0 \)\。我々のみを含む構築する必要が\(I \)を\(0 \)、すなわち再帰式ことができます。
場合\(C \ 0 = \) 、のみ再帰構築する必要が'\(R&LT \) 、(+ 1 | | R \' \当量のK <N \) 、\(\ I = {sum_を^ {} 1 | R&LT '| {K} A_ - R'_i I} = 0 \)、\(\ sum_ 1} ^ {I = {| R&LT' |} N-A_ { - } I = delta_n R'_i \)、次いで\(R_ {C + 1} = R_C + Rは、「\) 対象となります。
私達はちょうどC $ <$ 0 \当量のIDを探し 、 そのフロント- \(1 fail_ {ID} \) の数である\(0 \)その上で、我々は変位、すなわち、フロントフィル作る場合。(\ I - fail_ {ID} - 1 \) \(0 \)に続いて、\(1 \)、[接続\( - R_ {ID} \) 、我々は唯一の場所を得ることができる(\ I \ )である\(delta_time_unit_addressのID} {} {fail_ \) 、残りの位置である)\(0 \アレイ。我々乗算それ全体\(TMP = \ FRAC {delta_ {I}}、{{delta_ fail_ { }}} ID \) 、構築した\(R「を\)
すなわち\(R「\)の
\ [\ {0,0、... 0 、TMP、-tmp R_ {ID}(1)、 - TMP R_ {ID}(2)、... \} \ ]
その後、我々は確認する必要があります(\ R_C + R」)を\最短で、我々は見つける\(I - fail_上記のid}以上{+ | R_ {上記のid上記} | \) 。あなたができる最小(ない厳格な証明)
テンプレート
データはビューの週ガイダンスブログのポイントを行くことができます。
#pragma GCC optimize("2,Ofast,inline")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define LL long long
#define pii pair<int, int>
using namespace std;
const int mod = 1e9 + 7;
template <typename T> T read(T &x) {
int f = 0;
register char c = getchar();
while (c > '9' || c < '0') f |= (c == '-'), c = getchar();
for (x = 0; c >= '0' && c <= '9'; c = getchar())
x = (x << 3) + (x << 1) + (c ^ 48);
if (f) x = -x;
return x;
}
inline void upd(int &x, int y) {
(x += y) >= mod ? x -= mod : 0;
}
inline int add(int x, int y) {
return (x += y) >= mod ? x - mod : x;
}
inline int dec(int x, int y) {
return (x -= y) < 0 ? x + mod : x;
}
inline int Qpow(int x, int p) {
int ans = 1;
for (; p; p >>= 1) {
if (p & 1) ans = 1LL * ans * x % mod;
x = 1LL * x * x % mod;
}
return ans;
}
inline int Inv(int x) {
return Qpow(x, mod - 2);
}
namespace BM {
const int Maxn = 5005;
int n, c;
int a[Maxn], del[Maxn], fail[Maxn];
vector<int> R[Maxn];
vector<int> solve() {
c = 0;
for (int i = 1; i <= n; ++i) {
if (c == 0) {
if (a[i]) {
fail[0] = i;
++c;
del[i] = a[i];
fail[c] = i;
R[c].resize(i);
}
continue;
}
del[i] = a[i];
for (int j = 0; j < R[c].size(); ++j) {
del[i] = dec(del[i], 1LL * R[c][j] * a[i - j - 1] % mod);
}
if (del[i] == 0) continue;
fail[c] = i;
int id = c - 1, v = i - fail[id] + R[id].size();
for (int j = c - 1; j >= 0; --j) {
if (v > i - fail[j] + R[j].size()) {
v = i - fail[j] + R[j].size();
id = j;
}
}
int p = i - fail[id];
int tmp = 1LL * del[i] * Inv(del[fail[id]]) % mod;
R[c + 1] = R[c];
if (R[c + 1].size() < v) R[c + 1].resize(v);
upd(R[c + 1][p - 1], tmp);
for (int j = 0; j < R[id].size(); ++j) {
upd(R[c + 1][p + j], -1LL * tmp * R[id][j] % mod + mod);
}
++c;
}
if (c == 0) return vector<int>(0);
return R[c];
}
}
using namespace BM;
int main() {
read(n);
for (int i = 1; i <= n; ++i) read(a[i]);
vector<int> ans = BM::solve();
cout << ans.size() << endl;
for (int i = 0; i < ans.size(); ++i)
cout << ans[i] << ' ';
puts("");
}