Problem
【JLOI2015】有意义的字符串
TimeLimit:10Sec
MemoryLimit:128MB
Description
B君有两个好朋友,他们叫宁宁和冉冉。
有一天,冉冉遇到了一个有趣的题目:输入b,d,n,求
⌊(2b+d)n⌋mod7528443412579576937
一行三个整数b,d,n。
Output
一行一个数表示模7528443412579576937之后的结果。
Sample Output
Hint
0<b2≤d<(b+1)2≤1018,n≤1018,b≡1mod2,d≡1mod4。
标签:线性齐次递推
Solution
回忆二阶线性齐次递推的通项形式。
对于线性递推Aai+Bai−1+C=0,其特征方程为Ax2+Bx+C=0,设其两根为α,β。则通项的形式为ai=Pαi+Qβi,其中P,Q为可根据特解计算的待定系数。
可以构造一个序列{ai},使得其通项为ai=(2b+d)i+(2b−d)i,那么其特征方程的两根为α=2b+d,β=2b−d。于是可以还原其递推式,得到
ai−bai−1+4b2−d=0a0=2,a1=b,an=ban−1−4b2−dan−2
由于b≡1mod2,d≡1mod4,可知4∣b2−d,4b2−d为整数。可以构造转移矩阵,用矩阵快速幂计算an。
(an−1an−2)×(b−4b2−d10)=(anan−1)
接下来考虑如何根据ai计算答案。
由0<b2≤d<(b+1)2,可知2b−d∈(−21,0]。于是当2∣n时,(2b−d)n∈[0,21),有Ans=an−1;否则(2b−d)n∈(−21,0],有Ans=an。
综上,在矩阵快速幂后根据n的奇偶性调整答案即可。
Code
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
| #include <bits/stdc++.h> #define P 7528443412579576937 using namespace std; typedef long long lnt; typedef unsigned long long unt; template <class T> inline void read(T &x) { x = 0; int c = getchar(), f = 1; for (; !isdigit(c); c = getchar()) if (c == 45) f = -1; for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0'); } lnt n, b, d; lnt add(lnt x, lnt y) { unt s = (unt)x+(unt)y; return (lnt)(s%P); } lnt mul(lnt x, lnt y) { lnt ret = 0; if (x < y) swap(x, y); for (; y; x = add(x, x)%P, y >>= 1) if (y&1) ret = add(ret, x)%P; return ret; } struct Matrix { lnt ele[2][2]; Matrix () {memset(ele, 0, sizeof ele);} inline Matrix operator * (const Matrix &x) const { Matrix ret; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) for (int k = 0; k < 2; k++) ret.ele[i][j] = add(ret.ele[i][j], mul(ele[i][k], x.ele[k][j]))%P; return ret; } } a, m; Matrix Power(Matrix mat, lnt k) { Matrix ret; ret.ele[0][0] = 1; ret.ele[1][1] = 1; for (; k; k >>= 1, mat = mat*mat) if (k&1) ret = ret*mat; return ret; } int main() { read(b), read(d), read(n); if (!n) return puts("1"), 0; a.ele[0][0] = b, a.ele[0][1] = 2; m.ele[0][0] = b, m.ele[0][1] = 1; m.ele[1][0] = P-((mul(b, b)-d)>>2); a = a*Power(m, n-1), a.ele[0][0] -= !(n&1); return printf("%lld\n", a.ele[0][0]), 0; }
|