洛谷P3263有意义的字符串题解。
洛谷P3263
题意描述
给定 b、d 和 n。
试求出:
$\left \lfloor \left ( \frac{b+\sqrt{d} }{2} \right )^{n} \right \rfloor \bmod{p} $
其中 p=7528443412579576937 ,0<b2≤d<(b+1)2≤1018,n≤1018 且 bmod2=1,dmod4=1。
题解报告
式子较为复杂,看了下标签是“矩阵乘法”,更加蒙了。(原本都打算搞个 double 的矩阵了。。。)
想要让式子与矩乘挂上钩,首先想到要把那个根号给去掉。于是想到在原式后加一个式子使两者相加能将根号去掉。
由于有一个 n,可以想到将带根号的那一项取负,其他不变(暂不考虑取模和向下取整),然后原式变为:
(2b−d)n
在原式后加上现在这个式子便可将根号消掉,即:
(2b+d)n+(2b−d)n
然后在式子最后减去一个 (2b−d)n 就好了。
设 x 为 2b+d,y 为 2b−d。
设 f_n=xn+yn。
那么可以设我们的状态矩阵为:
[f_nf_n−1]
需要通过
[f_n−1f_n−2]
转移到
[f_nf_n−1]
接下来考虑如何转移。
将 f_n 拆成 X×f_n−1−X×f_n−2 的形式,又因为 f_n−1=xn−1+yn−1,f_n−2=xn−2+yn−2,代入得:
X×(xn−1+yn−1)−X×(xn−2+yn−2)
于是稍加考虑就可以得出:
xn+yn=(x+y)×(xn−1+yn−1)−xy×(xn−2+yn−2)
所以转移式为:
f_n=(x+y)×f_n−1−xy×f_n−2
能保证这个式子中没有任何浮点数吗?
我们发现 f_1=2b+d+2b−d=b,f_2=(2b+d)2+(2b−d)2=2b2+d。
b 一定是整数,而由于 bmod2=1,dmod4=1,由费马小定理可得 b2≡b(mod2),所以 b2+dmod2=0,所以 2b2+d 也是整数。
于是乎,f_1 和 f_2 都是整数,接下来只需证明出他俩前面的系数也是整数就好了。
首先易得 x+y=b,所以 x+y 是整数,然后 xy=4b2−d,由欧拉定理可得 bφ(4)=b2≡1(mod4),又因为 dmod4=1,所以 (b2−d)mod4=0,所以 xy 为整数。
综上,f_n 总为整数。
所以转移矩阵也同时推出来了。
如下:
[b −4b2−d10]
这里的 −4b2−d 为了方便可以写成 4d−b2。
最后再来看看刚才这个东西对答案的影响:
然后在式子最后减去一个 (2b−d)n 就好了。
由于答案是向下取整,所以当 −(2b−d)n 为正且大小在区间 [0,1) 时对答案无影响。
由于 $0 < b^{2} \le d < (b+1)^{2}\le 10^{18} $,所以 (2b−d)n 的范围一定在区间 [0,1) 内。
接下来只要讨论式子的正负性。
因为 0<b2≤d,所以 2b−d 一定小于 0。
当 nmod2=1 时,即 n 为奇数时,−(2b−d)n 一定的范围一定在 [0,1) 内,对答案没有影响。
相反,当 nmod2=0 时,−(2b−d)n 的范围在区间 (−1,0] 内。当式子等于 0 时,即 b=d,b2=d 时,该式对答案无影响。
综上,当且仅当 n 为偶数且 b2=d 时,该式对答案有影响,答案向下取整后的值需要减一。
说了一大堆,终于到了大家最爱的代码时间。
嗲吗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #define int long long #define ull unsigned long long
int tormul(int a, int k) { ull ans = 0; while (k) { if (k & 1)ans = (ans + a) % MOD; a = (ull)(a + a) % MOD; k >>= 1; } return ans; } struct mat { int a[2][2]; mat() { memset(a, 0, sizeof a); } mat operator *(const mat &b)const { mat op; for (int i = 0; i < 2; i++) for (int k = 0; k < 2; k++) for (int j = 0; j < 2; j++) op.a[i][j] = (ull)(op.a[i][j] + tormul(a[i][k], b.a[k][j])) % MOD; return op; } } ans, I; void init() { I.a[0][0] = b, I.a[0][1] = 1, I.a[1][0] = (d - b * b) / 4; ans.a[0][0] = (b * b + d) / 2, ans.a[0][1] = b; } signed main() { b = read(), d = read(), n = read(); init(); if (n == 0ll) { printf("1"); return 0; } else if (n == 1ll) { printf("%lld ", (int)((b + sqrt(d)) / 2) % MOD); return 0; } n -= 2; int ff = 0; if (b * b != d && n % 2 == 0) ff--; while (n) { if (n & 1)ans = ans * I; I = I * I; n >>= 1; } ans.a[0][0] += ff; printf("%lld ", ans.a[0][0]); return 0; }
|
有错误请 D 我