环鸽的数列(数列的通项,区间加等比数列,区间求和)

https://ac.nowcoder.com/acm/contest/5759/B

题意:

有一个递推数列 \{F_n\} ,F_1=1,\ F_2=3,\ F_n=3F_{n-1}+2F_{n-2} (n>2)

对于一个长度为 n 的区间,共有 m 次操作,每个操作给三个数字 op,l,r,你需要支持下面两种操作

op=1:区间 [l,\ r] 每个位置加上 F_{i-l+1}

op=2:输出区间 [l,\ r] 的和膜 998244353 的值


首先肯定要找到递推数列 \{F_n\} 的性质,显然直接在线段树上打标记是不行的,那么我们可以考虑先求出递推数列 \{F_n\} 的通项

首先假设 递推数列 \{F_n\} 的递推式为 F_n=aF_{n-1}+bF_{n-2} (n>2), 并且存在 s, r 满足 F_n-rF_{n-1}=s(F_{n-1}-rF_{n-2}),将这两个式子联立得到 ,可以求出 s, r = \frac{a\pm \sqrt{a^2+4b}}{2}

若 s=r

则 s=r=\frac{a}{2},将 s=r 代入 F_n-rF_{n-1}=s(F_{n-1}-rF_{n-2}) ,并且递推数列 \{F_n-F_{n-1}\} 是等比数列

F_n-rF_{n-1}=r(F_{n-1}-rF_{n-2}),继续化简得到 F_n=rF_{n-1}+r^{n-2}(F_{2}-rF_{1})

将 F_{n-1}=rF_{n-2}+r^{n-3}(F_2-rF_1)  代入上述式子得到 F_n=r^2F_{n-2}+2r^{n-2}(F_2-rF_1)

同理可以得到 F_n=r^{n-3}F_{3}+(n-3)r^{n-2}(F_2-rF_1)

将 F_3=rF_2+r(F_2-rF_1)=2rF_2-r^2F_1 代入上述式子得到

F_n=r^{n-3}*(2rF_2-r^2F_1)+(n-3)r^{n-2}*(F_2-rF_1)

化简得到 F_n=(n-1)F_2r^{n-2}-(n-2)F_1r^{n-1}

若 s\neq r

将 s,r 代入 F_n-rF_{n-1}=s(F_{n-1}-rF_{n-2}) 得到两个式子,并且递推数列 \{F_n-F_{n-1}\} 是等比数列

F_n-rF_{n-1}=s(F_{n-1}-rF_{n-2}),继续化简得到 F_n-rF_{n-1}=s^{n-2}(F_{2}-rF_{1})

F_n-sF_{n-1}=r(F_{n-1}-sF_{n-2}),继续化简得到 F_n-sF_{n-1}=r^{n-2}(F_{2}-sF_{1})

将 F_{n-1} 消掉得到 F_n=\frac{(F_2-rF_1)*s^{n-1}-(F_2-sF_1)*r^{n-1}}{s-r}

回到这个题目,首先得到 s,r=\frac{3\pm \sqrt{17}}{2},然后得到通项 F_n=\frac{1}{\sqrt{17}}((\frac{3+\sqrt{17}}{2})^n-(\frac{3-\sqrt{17}}{2})^n)

首先用二次剩余和逆元将式子中出现的根号和分数化为整数。

所以题目中的两个操作就变成了区间加等比数列,区间求和,然后使用两个线段树分别维护两个次方即可

Code:

// F_n = \frac{1}{\sqrt{17}}*((\frac{3+\sqrt{17}}{2})^n-(\frac{3-\sqrt{17}}{2})^n)
// F_n = inv_sqrt17*(x_0^n-x_1^n)
#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
#define lson left,mid,k<<1,op
#define rson mid+1,right,k<<1|1,op
#define imid int mid=(left+right)>>1;
using namespace std;
const int MAXN = 1e5 + 5;
const ll mod = 998244353;
const ll sqrt17 = 473844410;
const ll inv_sqrt17 = 438914993;
const ll x[2] = { 736044383,262199973 };
struct node
{
	int l;
	int r;
	ll mark;
	ll sum;
}que[MAXN * 4][2];
ll a[MAXN];
ll facq[MAXN][2];                          //power(x[op],i)
const ll inv[2] = { 932694360,315111081 }; //power(x[op]-1,mod-2)
void init()
{
	facq[0][0] = 1;
	facq[0][1] = 1;
	for (int i = 1; i < MAXN; i++)
	{
		facq[i][0] = facq[i - 1][0] * x[0] % mod;
		facq[i][1] = facq[i - 1][1] * x[1] % mod;
	}
}
ll power(ll a, ll b)
{
	ll res = 1;
	while (b)
	{
		if (b & 1)
			res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return res;
}
ll calcnth(ll a1, ll n, int op)
{
	ll an = a1 * facq[n - 1][op] % mod;
	return an;
}
ll calcsum(ll a1, ll n, ll op)
{
	ll q = x[op];
	ll an = a1 * facq[n - 1][op] % mod;
	ll ans = (an * q % mod - a1 + mod) * inv[op] % mod;
	return ans;
}
void up(int k, int op)
{
	que[k][op].sum = (que[k << 1][op].sum + que[k << 1 | 1][op].sum) % mod;
}
void down(int k, int op)
{
	if (que[k][op].mark)
	{
		que[k << 1][op].mark = (que[k << 1][op].mark + que[k][op].mark) % mod;
		que[k << 1][op].sum = (que[k << 1][op].sum + calcsum(que[k][op].mark, (que[k << 1][op].r - que[k << 1][op].l + 1), op)) % mod;
		ll rst = calcnth(que[k][op].mark, que[k << 1][op].r - que[k << 1][op].l + 1 + 1, op);
		que[k << 1 | 1][op].mark = (que[k << 1 | 1][op].mark + rst) % mod;
		que[k << 1 | 1][op].sum = (que[k << 1 | 1][op].sum + calcsum(rst, (que[k << 1 | 1][op].r - que[k << 1 | 1][op].l + 1), op)) % mod;
		que[k][op].mark = 0;
	}
}
void build(int left, int right, int k, int op)
{
	que[k][op].l = left;
	que[k][op].r = right;
	que[k][op].mark = 0;
	que[k][op].sum = 0;
	if (left == right)
	{
		que[k][op].sum = 0;
		return;
	}
	imid;
	build(lson);
	build(rson);
	up(k, op);
}
void update(int left, int right, int k, int op, int ql, int qr, ll val)
{
	if (qr < left || right < ql)
		return;
	if (ql <= left && right <= qr)
	{
		ll st = calcnth(val, left - ql + 1, op);
		que[k][op].mark = (que[k][op].mark + st) % mod;
		que[k][op].sum = (que[k][op].sum + calcsum(st, que[k][op].r - que[k][op].l + 1, op)) % mod;
		return;
	}
	down(k, op);
	imid;
	update(lson, ql, qr, val);
	update(rson, ql, qr, val);
	up(k, op);
}
ll query(int left, int right, int k, int op, int ql, int qr)
{
	if (qr < left || right < ql)
		return 0;
	if (ql <= left && right <= qr)
		return que[k][op].sum;
	down(k, op);
	imid;
	return (query(lson, ql, qr) + query(rson, ql, qr)) % mod;
}
int main()
{
	init();
	int n, m;
	sc("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
	{
		sc("%lld", &a[i]);
		a[i] = (a[i] + a[i - 1]) % mod;
	}
	build(1, n, 1, 0);
	build(1, n, 1, 1);
	while (m--)
	{
		int op, ql, qr;
		sc("%d%d%d", &op, &ql, &qr);
		if (op == 1)
		{
			update(1, n, 1, 0, ql, qr, x[0]);
			update(1, n, 1, 1, ql, qr, x[1]);
		}
		else
		{
			ll ans1 = query(1, n, 1, 0, ql, qr);
			ll ans2 = query(1, n, 1, 1, ql, qr);
			ll ans = inv_sqrt17 * (ans1 - ans2 + mod) % mod;
			ans = (ans + a[qr] - a[ql - 1] + mod) % mod;
			pr("%lld\n", ans);
		}
	}
}
/*
4 2
0 0 0 0
1 1 1 
2 1 1
*/

 

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术工厂 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读