[省选] [线段树] [矩阵快速幂] [HLOI2016] 序列问题

问题描述 Description

现定义序列它的第 i i i项为: F i = S i − 1 ∗ F i − 1 + S i − 2 ∗ F i − 2 F_i=S_{i-1}*F_{i-1}+S_{i-2}*F_{i-2} Fi=Si1Fi1+Si2Fi2 定义 F 0 = 0 F_0=0 F0=0以及 F 1 = 1 F_1=1 F1=1
其中, S S S是一个无限长的,几乎循环的一个数字序列,它的循环节长度为 N N N,也就是说,通常会有 S i = S i   m o d   N S_i=S_{i\bmod N} Si=SimodN。但是 S S S中也存在少数元素并不符合这个循环节,也就是说,会有若干个元素, S i ≠ S i   m o d   N S_i\not=S_{i\bmod N} Si=SimodN
现在给出序列 S S S的循环节,以及 S S S中不符合循环的位置以及值,求 F k   m o d   P F_k\bmod P FkmodP

输入 Input

输入文件的第一行有两个整数 K K K P P P
第二行是一个整数 N N N
第三行包含 N N N个正整数,表示循环节中所有的数字。
接下来一行是一个整数 M M M。接下来的 M M M行,每行包含两个整数 x x x y y y,表示在序列 S S S中不符合循环节的位置以及相应位置上的值,即 S x = y S_x=y Sx=y

输出 Output

输出文件包含一个整数,即相应输入文件的答案。

样例输入 Sample Input

42 1248493
5
5 2 4 1 6
5
9 3
8 4
21 21
10 18
24 10

样例输出 Sample Output

232959

限制 Limits

对于30%的数据: 0 ≤ k ≤ 10000 , 1 ≤ n ≤ 1000 , 1 ≤ M ≤ 20 0\le k\le 10000,1\le n\le 1000,1\le M\le 20 0k10000,1n1000,1M20
对于70%的数据: 0 ≤ k ≤ 1 0 18 , 1 ≤ n ≤ 1000 , 1 ≤ M ≤ 20 0\le k\le 10^{18},1\le n\le 1000,1\le M\le 20 0k1018,1n1000,1M20
对于100%的数据: 0 ≤ k ≤ 1 0 18 , 1 ≤ n , m ≤ 5 × 1 0 4 , 1 ≤ p ≤ 1 0 9 , 1 ≤ S i ≤ 1 0 9 , n ≤ x ≤ 1 0 18 , 1 ≤ y ≤ 1 0 9 0\le k\le 10^{18},1\le n,m\le 5\times 10^4,1\le p\le 10^9,1\le S_i\le 10^9,n\le x\le 10^{18},1\le y\le 10^9 0k1018,1n,m5×104,1p109,1Si109,nx1018,1y109
Time Limit : 2 s 2s 2s & Memory Limit : 128 M B 128MB 128MB

一看 k k k这么大快速幂逃不掉了…
一看递推关系矩阵逃不掉了…
所以矩阵快速幂逃不掉了。
MDZZ怎么搞矩阵?
这回在化学课上推公式…
f 0 = 0 f 1 = 1 f 2 = s 1 f 1 = s 1 f 3 = s 2 f 2 + s 1 f 1 = s 1 s 2 + s 1 f 4 = s 3 f 3 + s 2 f 2 = s 1 s 2 s 3 + s 1 s 2 + s 1 s 3 … \begin{aligned} f_0&=0\\ f_1&=1\\ f_2&=s_1f_1=s_1\\ f_3&=s_2f_2+s_1f_1=s_1s_2+s_1\\ f_4&=s_3f_3+s_2f_2=s_1s_2s_3+s_1s_2+s_1s_3\\ &\dots \end{aligned} f0f1f2f3f4=0=1=s1f1=s1=s2f2+s1f1=s1s2+s1=s3f3+s2f2=s1s2s3+s1s2+s1s3
看出什么来了吗?
反正我看了一天
可以看出这个 f f f只与 s s s有关…
假如能搞出一个矩阵的话,可以借鉴分块思想,将一个循环节看成一个块,将整个块内的值求出后,跑矩阵快速幂,之后零散部分暴力。
可是有修改…
就将修改看成断点,假如断点处于同一块内,暴力即可,如果不在,零散暴力,整块快速幂。
时间为 O ( m n log ⁡ 2 k ) O(mn\log_2 k) O(mnlog2k)
这样可以过 70 % 70\% 70%
100 % 100\% 100%优化的是零散部分,因为要不停计算零散部分,这些零散部分还是循环的,所以可以用线段树优化。
时间为 O ( m log ⁡ 2 n log ⁡ 2 k ) O(m\log_2 n\log_2 k) O(mlog2nlog2k)
所以,怎么构造矩阵?
还是两个矩阵,一个是处理影响的,一个是统计答案的。
统计答案的矩阵是一个 1 × 2 1\times2 1×2的矩阵:
[ f a + 1 f a ] \begin{bmatrix} f_{a+1}& f_a \end{bmatrix} [fa+1fa]
当然也可以写成 2 × 2 2\times2 2×2的,其余补 0 0 0即可。
处理影响的矩阵是一个 2 × 2 2\times2 2×2的矩阵:
[ 0 s a 1 s a + 1 ] \begin{bmatrix} 0 & s_{a}\\ 1 & s_{a+1} \end{bmatrix} [01sasa+1]
遇到断点答案矩阵暴力乘矩阵即可,此矩阵为:
[ 0 s x − 1 1 c ] \begin{bmatrix} 0&s_{x-1}\\ 1&c \end{bmatrix} [01sx1c]
其中 x x x为需要修改的位置, c c c为变换成的数。
这还没完,因为矩阵与 x + 1 x+1 x+1位置也有关,还需要乘:
[ 0 c 1 s x + 1 ] \begin{bmatrix} 0&c\\ 1&s_{x+1} \end{bmatrix} [01csx+1]
这样就可以了
还有一些许多细节需要注意…具体参见代码。
Code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值