幼儿园数学题II
ssl 2514
题目大意
给出式子
f(1)=1,f(2)=1f(1)=1,f(2)=1f(1)=1,f(2)=1
f(n)−f(3)−f(4)−f(5)−...−f(n−3)−f(n−2)=(n+4)(n−1)/2f(n)-f(3)-f(4)-f(5)-...-f(n-3)-f(n-2)=(n+4)(n-1)/2f(n)−f(3)−f(4)−f(5)−...−f(n−3)−f(n−2)=(n+4)(n−1)/2
让你求前n项的和(对109+710^9+7109+7取模)
输入样例#1
1
输出样例#1
1
输入样例#2
2
输出样例#2
2
数据范围
0⩽n⩽231−10\leqslant n\leqslant 2^{31}-10⩽n⩽231−1
解题思路
f(n)=(n+4)(n−1)/2+f(3)+f(4)+f(5)+…+f(n−3)+f(n−2)f(n)=(n+4)(n-1)/2+f(3)+f(4)+f(5)+…+f(n-3)+f(n-2)f(n)=(n+4)(n−1)/2+f(3)+f(4)+f(5)+…+f(n−3)+f(n−2)
n很大,不能直接递推
考虑矩阵乘法
对于后面的一堆fff我们可以用前缀和
我们设矩阵
[si−2fi−1(n+4)⋅(n−1)2n1]\begin{bmatrix}s_{i-2} & f_{i-1} & \frac{(n+4)\cdot (n-1)}{2} & n & 1\end{bmatrix}[si−2fi−12(n+4)⋅(n−1)n1]
si−1=si−2+fi−1s_{i-1}=s_{i-2}+f_{i-1}si−1=si−2+fi−1
fi=(n+4)⋅(n−1)2+si−2f_{i}=\frac{(n+4)\cdot (n-1)}{2}+s_{i-2}fi=2(n+4)⋅(n−1)+si−2
把 (n+4)⋅(n−1)2\frac{(n+4)\cdot (n-1)}{2}2(n+4)⋅(n−1)展开得到n2+3⋅n−42\frac{n^2 + 3\cdot n - 4}{2}2n2+3⋅n−4
((n+1)+4)⋅((n+1)−1)2=(n+5)⋅n2=n2+5⋅n2=n2+3⋅n−4+2⋅n+42=(n+4)⋅(n−1)2+n+4\frac{((n+1)+4)\cdot ((n+1)-1)}{2}=\frac{(n+5)\cdot n}{2}=\frac{n^2 + 5\cdot n}{2}=\frac{n^2 + 3\cdot n - 4+2\cdot n + 4}{2}=\frac{(n+4)\cdot (n-1)}{2}+n+42((n+1)+4)⋅((n+1)−1)=2(n+5)⋅n=2n2+5⋅n=2n2+3⋅n−4+2⋅n+4=2(n+4)⋅(n−1)+n+4
然后可以得到矩阵
[1100010000011000011000211]\begin{bmatrix}1 & 1 & 0 & 0 & 0\\ 1 & 0 & 0 & 0 & 0\\ 0 & 1 & 1 & 0 & 0\\ 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 2 & 1 & 1\end{bmatrix}⎣⎢⎢⎢⎢⎡1100010100001120001100001⎦⎥⎥⎥⎥⎤
然后快速幂即可
但出题人的方法在计算f3f_3f3时会减去1??
但问题不大,预处理一下即可
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define wyc 1000000007
using namespace std;
ll n;
struct matrix
{ll n, m, a[10][10];matrix operator *(const matrix &b) const{matrix c;c.n = n;c.m = b.m;for (int i = 1; i <= c.n; ++i)for (int j = 1; j <= c.m; ++j)c.a[i][j] = 0;for (int i = 1; i <= c.n; ++i)for (int k = 1; k <= m; ++k)for (int j = 1; j <= c.m; ++j)c.a[i][j] = (c.a[i][j] + a[i][k] * b.a[k][j] % wyc) % wyc;return c;}
}A, B;
void Counting(ll x)
{while(x){if (x&1) A = A * B;B = B * B;x>>=1;}
}
int main()
{scanf("%lld", &n);if (n <= 3){if (n == 1) putchar('1');else if (n == 2) putchar('2');else if (n == 3) putchar('8');return 0;}A.n = 1;A.m = B.n = B.m = 5;A.a[1][1] = 0, A.a[1][2] = 6, A.a[1][3] = 12, A.a[1][4] = 4, A.a[1][5] = 1;//初始状态,前两个不算进去B.a[1][1] = 1, B.a[1][2] = 1, B.a[1][3] = 0, B.a[1][4] = 0, B.a[1][5] = 0;B.a[2][1] = 1, B.a[2][2] = 0, B.a[2][3] = 0, B.a[2][4] = 0, B.a[2][5] = 0;B.a[3][1] = 0, B.a[3][2] = 1, B.a[3][3] = 1, B.a[3][4] = 0, B.a[3][5] = 0;B.a[4][1] = 0, B.a[4][2] = 0, B.a[4][3] = 1, B.a[4][4] = 1, B.a[4][5] = 0;B.a[5][1] = 0, B.a[5][2] = 0, B.a[5][3] = 2, B.a[5][4] = 1, B.a[5][5] = 1;Counting(n - 2);//初始是s_2printf("%lld", A.a[1][1] + 2);//把前两个加进去return 0;
}