像一般的數列維護一樣,這題也差不多。有乙個數列a,修改操作是將a[i] .. a[j]的值都加上乙個d,詢問操作就有點不同,給出i和j,求出a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i)模上乙個數的結果。其中fib就是斐波納契數列,即fib(0) = fib(1) = 1,對於fib(i)(> 1), fib(i) = fib(i -1) + fib(i - 2)。
已知a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i)或者儲存多一些需要的資訊,怎樣求出a[i] * fib(0+ k) + a[i + 1] * fib(1+ k) + a[i + 2] * fib(2+ k) + ... + a[j] * fib(j - i+ k)。
斐波納契數列有乙個奇特的性質,嘗試如下的運算,得出的序列還是斐波納契數列。
a 1 1 2 3 5 8 13 ....
b 1 2 3 5 8 13 21 ....
將同乙個位置的相加(c[i] = a[i] + b[i]),得:
c 2 3 5 8 13 21 34 ....
再加加d[i] = b[i] + c[i],得:
d 3 5 8 13 21 34 55
如此看來,我們可以設:
x = a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i);
y = a[i] * fib(1) + a[i + 1] * fib(2) + a[i + 2] * fib(3) + ... + a[j] * fib(j - i + 1);
那麼:x + y = a[i] * fib(2) + a[i + 1] * fib(3) + a[i + 2] * fib(4) + ... + a[j] * fib(j - i + 2);
x + 2y = a[i] * fib(3) + a[i + 1] * fib(4) + a[i + 2] * fib(5) + ... + a[j] * fib(j - i + 3);
2x + 3y = a[i] * fib(4) + a[i + 1] * fib(5) + a[i + 2] * fib(6) + ... + a[j] * fib(j - i + 4);
3x + 5y = a[i] * fib(5) + a[i + 1] * fib(6) + a[i + 2] * fib(7) + ... + a[j] * fib(j - i + 5);
fib(k - 2) * x + fib(k - 1) * y = a[i] * fib(0+ k) + a[i + 1] * fib(1+ k) + a[i + 2] * fib(2+ k) + ... + a[j] * fib(j - i+ k) (k > 1),k = 0,k = 1的情況額外處理,fib數列預處理。
這樣,我們就可以實現維護了,需要儲存兩個資訊,就是上述的x,y。接著就是資訊傳遞的操作,也就是整段都加上d。
也就是已知a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i),求(a[i]+ d) * fib(0) + (a[i + 1]+ d) * fib(1) + (a[i + 2]+ d) * fib(2) + ... + (a[j]+ d) * fib(j - i)。
通過拆分得:a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i) +d * fib(0) + d * fib(1) + d * fib(2) + ... + d * fib(j - i)
a[i] * fib(0) + a[i + 1] * fib(1) + a[i + 2] * fib(2) + ... + a[j] * fib(j - i) +d * (fib(0) + fib(1) + fib(2) + ... + fib(j - i))。
fib的數列和有個定理:fib(0) + fib(1) + fib(2) + ... + fib(i) = fib(i + 2) - 1。這樣又可以實現資訊傳遞的操作了。問題到此就解決了。此外,我們可以從fib的矩陣乘法中聯想到合併資訊的方法,本質是一樣的。
對於一些比較難維護的資料,可以通過列公式等方法找出其中的規律,哪怕沒有什麼規律,我們也能從中得到一些啟發。還可以想想另一些方法,即使它們看起來是不能解決問題的。
#include #include using namespace std;
typedef long long ll;
typedef pairpii;
const ll mod = 1000000000ll;
const int n = 200007;
int n, m;
ll fib[n], x[n], y[n];
int nnode = 1;
struct node
inline int size()
}node[n << 1], *root = &node[0];
inline pii calc(pii a, int k)
pii operator + (pii const &a, pii const &b)
void build(node *p, int le, int ri)
else }
void update(node *p, ll flag)
void modify(node *p, int le, int ri, ll delta)
int mi = p -> mi();
if (le < mi) modify(p -> lch, le, ri, delta);
if (ri > mi) modify(p -> rch, le, ri, delta);
p -> dat = p -> lch -> dat +
calc(p -> rch -> dat, p -> lch -> size()); }}
pii ask(node *p, int le, int ri)
int mi = p -> mi();
if (le < mi && ri > mi)
return ask(p -> lch, le, ri) +
calc(ask(p -> rch, le, ri),
p -> lch -> hi - max(le, p -> lch -> lo));
else if (le < mi) return ask(p -> lch, le, ri);
else return ask(p -> rch, le, ri);
}void init()
void solve()
else
}}int main()
斐波納契數列
f 1 0 f 2 1 f n f n 1 f n 2 斐波納契數列決定審美和諧性 800年前,義大利的數學家李奧納多 斐波那契出版了驚世之作 算盤書 在 算盤書 裡,斐波納契提出了著名的 兔子生兔子的問題 有乙個人把一對兔 子放在四面圍著的地方。假定每個月一對兔子生下另外一對。而這新的一對在二個月...
斐波納契數列
斐波納契數列又稱 分割數列 因數學家列昂納多 斐波那契 leonardoda fibonacci 以兔子繁殖為例子而引入,故又稱為 兔子數列 指的是這樣乙個數列 1 1 2 3 5 8 13 21 34 此本章通過多種方式實現斐波納契數列 第一種 for 迴圈實現 a,b 0,1 for i in ...
python斐波納契數列
fibonacci series 斐波納契數列 兩個元素的總和確定了下乙個數 a,b 0,1 while b 10 print b a,b b,a b fibonacci series 斐波納契數列 兩個元素的總和確定了下乙個數 a,b 0,1 while b 1000 if a b 1000 pr...