1.题目链接。网上很多题解都说是打表找规律,tql。这个题我写了2h多,从推导,到打表。知道最后才发现规律。因为最后的答案要求的是sqrt(an)%mod(mod=1e9+7),所以我分析了半天发现只能是sqrt(an)这个东西存在线性递推公式,队友说也有可能是在n达到一定的值的时候,4^n成为an的主要贡献值,所以开方的主要矛盾就是4^n.最后证明这个想法是错的。an的数量级是没办法用某个部分确定下来的,所以我继续尝试寻找sqrt(an)的线性递推公式,如果找到它,直接使用快速幂解决。然后暴力的高斯消元,数据实在是太大了,解方程都没法解,最后都绝望了,然后观察到hn的递推后边-16,an又加了4的n次方。这是故意的吧,然后就把hb线性递推的系数带进去,完美符合。行吧,也算是解决了。最后看网上的一份比较靠谱的说法是:BM线性递推找规律。行吧,又学到了新东西。也提醒了我,要大胆的猜想。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct Sarray
{
static const ll LEN = 105;
static const ll mod = 1e9 + 7;
ll len, data[LEN][LEN];
Sarray(ll len, ll flag) :len(len) {
for (ll i = 0; i < len; i++) {
for (ll j = 0; j < len; j++)data[i][j] = 0;
data[i][i] = flag;
}
}
Sarray operator *(const Sarray&a) {
Sarray tem(a.len, 0);
for (ll i = 0; i < len; i++) {
for (ll j = 0; j < len; j++) {
for (ll k = 0; k < len; k++) {
tem.data[i][j] = (tem.data[i][j] + data[i][k] * a.data[k][j]) % mod;
}
}
}
return tem;
}
Sarray operator +(const Sarray&a) {
Sarray tem(a.len, 0);
for (ll i = 0; i < len; i++) {
for (ll j = 0; j < len; j++) {
tem.data[i][j] = (data[i][j] + a.data[i][j]) % mod;
}
}
return tem;
}
};
Sarray qpow(Sarray a, ll b) {//会更改a,不能按引用传递
Sarray tem(a.len, 1);
while (b) {
if (b & 1)tem = a * tem;
a = a * a;
b >>= 1;
}
return tem;
}
Sarray sigma(Sarray&p, ll n)
{
Sarray E(p.len, 1);
if (n == 0)return E;
if (n == 1)return E + p;
if (n & 1) return (E + qpow(p, n / 2 + 1))*sigma(p, n >> 1);
else return (E + qpow(p, n / 2 + 1))*sigma(p, n / 2 - 1) + qpow(p, n >> 1);
}
Sarray a(3, 0), org(3, 0), ans_array(3, 0);
int main() {
a.data[0][0] = 4;
a.data[0][1] = 17;
a.data[0][2] = Sarray::mod - 12;
a.data[1][0] = 1;
a.data[2][1] = 1;
org.data[0][0] = 1255;//n=4
org.data[1][0] = 197;//n=3
org.data[2][0] = 31;//n=2
ll ans[5] = { 0,0,31,197,1255 };
ll T;
scanf("%lld", &T);
while (T--) {
ll n;
scanf("%lld", &n);
if (n <= 4) {
printf("%lld\n", ans[n]);
}
else {
ans_array = qpow(a, n - 4)*org;
printf("%lld\n", ans_array.data[0][0]);
}
}
}