【BZOJ 5222】[Lydsy2017省队十连测] 怪题

# 【BZOJ 5222】[Lydsy2017省队十连测]怪题

## problem

就是要求一个奇怪的递推式子 $F_n = F_{n-1}+F_{n-2}+2*\sqrt{3+F_{n-1}F_{n-2}}$ 的第n项 $mod\ M$的值, 给定 $F_1$和 $F_2$

然后保证 $\sqrt{3+F_{n-1}F_{n-2}}$ 是个整数

$0 \leq n \leq 1e9 ,1 \leq m \leq 1e9 ,1 \leq F_0 \leq F_1 \leq 1e6$

## solution

* $[80pts]$ $[0 \leq n \leq 1e5]$

这题看到一开始还以为直接递推就行了,后来发现根号这玩意儿好像根本不能取模……还好看机房里其他大佬迟迟不下键盘,我犹豫了一会儿才发现。

好进入正题,看到递推式就要想到化简转化什么什么的,这题一定是想办法把根号去掉,考场上折腾一番,尝试尝试两边平方、多带入几层等等,于是……

$F_{n+1} = F_n+F_{n-1}+2\sqrt{3+F_nF_{n-1}}$

处理下根号里面的内容,带入$ F_n $:

$3+F_nF_{n-1} = 3+(F_{n-1}+F{n-2}+2\sqrt{3+F_{n-1}F_{n-2}}) \times F_{n-1}n = (3+F_{n-1}F{n-2}) + (F_{n-1}+2\sqrt{3+F_{n-1}F_{n-2}}) \times F_{n-1}$

然后考虑消掉一些项(考场上先想到的其实是下面这个东西,结果只是辅助):

$F_{n+1} = F_n+F_{n-1}+2\sqrt{3+F_nF_{n-1}}(F_{n+1}-F_n-F_{n-1})^2 = 4 \times (3+F_nF_{n-1})$

这样就可以做些替换了,继续之前的式子:

$3+F_nF_{n-1}=\frac{(F_{n+1}-F_n-F_{n-1})^2}{4}+F_{n-1} \times (F_n-F_{n-2})$

暴力拆开合并一下(这玩意儿太长了不写了~~不是我懒是因为太长影响阅读体验~~)得到:

$3+F_nF_{n-1}=(F_n^2+F_{n-1}^2+F_{n-2}^2-2F_nF_{n-2}-2F_{n-1}F_{n-2}+2F_nF_{n-1})\div 4 = (F_{n}+F_{n-1}-F_{n-2})^2\div 4$

带回最初的式子得到:

$F_{n+1}=2F_n+2F_{n-1}-F_{n-2}$

这就是最终的递推式了,可以直接递推加取模运算,另外注意$F_2$还要特殊计算一下,$80pts\ get$……

* $[100pts]$

一看到这种+-法的递推式就想到了矩阵乘法,折腾个矩阵乘法,搞个快速幂运算就行了

$\begin{bmatrix}
F_{n-3}&F_{n-2}&F_{n-1}\\0&0&0\\0&0&0\\
\end{bmatrix}$
$\times$
$\begin{bmatrix}
0&0&-1\\1&1&2\\0&0&2\\
\end{bmatrix}$
$=$
$\begin{bmatrix}
F_{n-2}&F_{n-1}&F_{n}\\0&0&0\\0&0&0\\
\end{bmatrix}$

就酱紫$100pts\ get$。

下面是我的代码,不会写矩阵乘法qwq折腾死我了……

```cpp
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::sqrt;
typedef long long ll;
const int N = 1e3+5;
const int C = 1e5+5;
const int inf = 1e9+7;
#define Reset(x, y) memset(x, y, sizeof(x))
#define Clean(x) Reset(x, 0)
#define qwq register
#define OvO inline
// const int MAXIN = 1e6;
// char IN[MAXIN],*SS=IN,*TT=IN;
// #define getchar() (SS == TT&&(TT = (SS=IN) + fread(IN,1,MAXIN,stdin), SS==TT) ? EOF:*SS++)
template <typename T> OvO T max(T a, T b) { return a > b ? a : b; }
template <typename T> OvO T min(T a, T b) { return a < b ? a : b; }
template <typename T> OvO void read(T &x) {
x = 0; T f = 1; char c = getchar();
while (c<'0' || c>'9') { if (c=='-') f=-1; c = getchar(); }
while (c>='0' && c<='9') { x = x*10+c-'0'; c = getchar(); }
x *= f;
}
bool mark1;
int n; ll mod;
ll _E[3][3] = { {1, 1, 1}, {1, 1, 1}, {1, 1, 1} };
ll _B[3][3] = { {0, 0, -1}, {1, 0, 2}, {0, 1, 2} };
struct Matrix {
ll a[3][3];
Matrix() { Reset(a, 0); }
} E, B, F;
Matrix mul(Matrix A, Matrix B) {
Matrix C;
for (int i = 0; i < 3; ++i)
for (int k = 0; k < 3; ++k)
for (int j = 0; j < 3; ++j)
C.a[i][j] = (C.a[i][j] + A.a[i][k] * B.a[k][j]) % mod;
return C;
}
Matrix solve(Matrix A, int p) {
Matrix ret = F;
while (p) {
if (p&1) ret = mul(ret, A);
A = mul(A, A);
p >>= 1;
}
return ret;
}
bool mark2;
int main()
{
// freopen("testin.txt", "r", stdin);
// freopen("stdout.txt", "w", stdout);
// freopen("testout.txt", "w", stdout);
// printf("Memory:%lfMB\n", (&mark2-&mark1)/1000.0/1000.0);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
B.a[i][j] = _B[i][j];
E.a[i][j] = _E[i][j];
}
}
read(F.a[0][0]); read(F.a[0][1]); read(mod); read(n);
F.a[0][2] = ( F.a[0][0]+F.a[0][1] + 2LL*(ll)sqrt(3+F.a[0][0]*F.a[0][1]) ) % mod;
if (n < 3) { printf("%lld\n", F.a[0][n]); return 0; }
F = solve(B, n-2);
printf("%lld\n", F.a[0][2]);
return 0;
}
```

猜你喜欢

转载自www.cnblogs.com/IrisEuclase/p/10534399.html