1.洛谷 P1962 斐波那契数列
题意
大家都知道,斐波那契数列是满足如下性质的一个数列:
F n = { 1 ( n ≤ 2 ) F n − 1 + F n − 2 ( n ≥ 3 ) F_n = \left\{\begin{aligned} 1 \space (n \le 2) \\ F_{n-1}+F_{n-2} \space (n\ge 3) \end{aligned}\right. Fn={1 (n≤2)Fn−1+Fn−2 (n≥3)
请你求出 F n m o d 1 0 9 + 7 F_n \bmod 10^9 + 7 Fnmod109+7 的值。
1 ≤ n < 2 63 1\le n < 2^{63} 1≤n<263。
思路
F i − 1 F i \] = \[ F i − 2 F i − 1 \] ⋅ \[ 0 1 1 1 \] \\begin{bmatrix} F_{i-1} \& F_{i} \\end{bmatrix} =\\begin{bmatrix} F_{i-2} \&F_{i-1} \\end{bmatrix}\\cdot \\begin{bmatrix} 0 \& 1\\\\ 1 \& 1 \\end{bmatrix} \[Fi−1Fi\]=\[Fi−2Fi−1\]⋅\[0111
2.SMOJ 数列1
题意
有一个数列:
f n = { 0 ( n ≤ 2 ) 7 f n − 1 + 6 f n − 2 + 4 × 3 n ( n ≥ 3 ) f_n = \left\{\begin{aligned} 0 \ (n \le 2) \\ 7f_{n-1}+6f_{n-2}+4\times 3^n \ (n\ge 3) \end{aligned}\right. fn={0 (n≤2)7fn−1+6fn−2+4×3n (n≥3)
请你求出 f n m o d 1 0 9 + 7 f_n \bmod 10^9 + 7 fnmod109+7 的值。
3 ≤ n ≤ 1 0 9 3\le n \le 10^9 3≤n≤109。
思路
f i − 1 f i 4 × 3 i + 1 \] = \[ f i − 2 f i − 1 4 × 3 i \] ⋅ \[ 0 6 0 1 7 0 0 1 3 \] \\begin{bmatrix} f_{i-1} \& f_i \&4\\times3\^{i+1}\\end{bmatrix}=\\begin{bmatrix} f_{i-2} \& f_{i-1} \& 4\\times 3\^i\\end{bmatrix}\\cdot \\begin{bmatrix} 0 \& 6 \& 0\\\\ 1 \& 7 \& 0\\\\ 0 \& 1 \& 3 \\end{bmatrix} \[fi−1fi4×3i+1\]=\[fi−2fi−14×3i\]⋅ 010671003
## 3.SMOJ 数列2
### 题意
有一个数列:
f n = { 0 ( n ≤ 2 ) 7 f n − 1 + 6 f n − 2 + 4 × 3 n + 5 n ( n ≥ 3 ) f_n = \\left\\{\\begin{aligned} 0 \\ (n \\le 2) \\\\ 7f_{n-1}+6f_{n-2}+4\\times 3\^n+5n \\ (n\\ge 3) \\end{aligned}\\right. fn={0 (n≤2)7fn−1+6fn−2+4×3n+5n (n≥3)
请你求出 f n m o d 1 0 9 + 7 f_n \\bmod 10\^9 + 7 fnmod109+7 的值。
### 思路
\[ f i − 1 f i 4 × 3 i + 1 5 ( i + 1 ) 5 \] = \[ f i − 2 f i − 1 4 × 3 i 5 i 5 \] ⋅ \[ 0 6 0 1 0 1 7 0 1 0 0 1 3 1 0 0 1 0 1 0 0 0 0 1 1 \] \\begin{bmatrix} f_{i-1} \& f_i \& 4\\times 3\^{i+1} \& 5(i+1) \& 5 \\end{bmatrix}= \\begin{bmatrix} f_{i-2} \& f_{i-1} \& 4\\times 3\^i \& 5i \& 5 \\end{bmatrix}\\cdot\\begin{bmatrix} 0 \& 6 \& 0 \& 1 \& 0\\\\ 1 \& 7 \& 0 \& 1 \& 0\\\\ 0 \& 1 \& 3 \& 1 \& 0\\\\ 0 \& 1 \& 0 \& 1 \& 0\\\\ 0 \& 0 \& 0 \& 1 \& 1 \\end{bmatrix} \[fi−1fi4×3i+15(i+1)5\]=\[fi−2fi−14×3i5i5\]⋅ 0100067110003001111100001
## 4.SMOJ 幸运数
### 题意
小明认为只有数字 4 4 4 和 7 7 7 是幸运数字,其他数字都不是。如果一个整数的每个数字都是幸运数字,那么该整数就是幸运整数。
给出一个数组 n u m b e r s 1... n numbers_{1...n} numbers1...n。
一个长度为 L L L 的幸运数列 A 0... L − 1 A_{0...L-1} A0...L−1 必须同时满足:
1. ∀ i ∈ \[ 0 , L ) \\forall i\\in\[0,L) ∀i∈\[0,L), A i A_i Ai 必须是幸运整数。
2. ∀ i ∈ \[ 0 , L ) \\forall i\\in\[0,L) ∀i∈\[0,L), A i A_i Ai 的最后一个数字必须等于 A \[ i + 1 \] A\[i+1\] A\[i+1\] 的第一个数字。
3. ∀ i ∈ \[ 0 , L ) \\forall i\\in\[0,L) ∀i∈\[0,L),至少存在一个下标 j j j 满足 A i = n u m b e r s j A_i=numbers_j Ai=numbersj。
输出有多少个不同的长度为L的幸运序列,答案模 1234567891 1234567891 1234567891。
对于两个长度都是L的幸运序列 A 0... L − 1 A_{0...L- 1} A0...L−1 和 B 0... L − 1 B_{0...L - 1} B0...L−1,他们被认为是不同序列的条件是: ∃ i , A i ≠ B i \\exist i,A_i\\neq B_i ∃i,Ai=Bi。
1 ≤ n ≤ 50 , 1 ≤ n u m b e r s i ≤ 1 0 9 , 1 ≤ L ≤ 1 0 9 1\\le n\\le 50,1\\le numbers_i\\le 10\^9,1\\le L\\le 10\^9 1≤n≤50,1≤numbersi≤109,1≤L≤109
### 思路
对所有幸运数分类:
1. 4 4 4 头 4 4 4 尾
2. 4 4 4 头 7 7 7 尾
3. 7 7 7 头 4 4 4 尾
4. 7 7 7 头 7 7 7 尾
用一个桶 c n t cnt cnt 记个数。
令 f i , t y p e f_{i,type} fi,type 表示前 i i i 个幸运数组成的序列中,序列最后一个数种类为 t y p e ∈ \[ 1 , 4 \] type\\in \[1,4\] type∈\[1,4\] 的方案数。
那么容易写出转移式子:
f i , 1 = f i − 1 , 1 ⋅ c n t 1 + f i − 1 , 3 ⋅ c n t 1 f_{i,1}=f_{i-1,1}\\cdot cnt_1+f_{i-1,3}\\cdot cnt_1 fi,1=fi−1,1⋅cnt1+fi−1,3⋅cnt1
f i , 2 = f i − 1 , 1 ⋅ c n t 2 + f i − 1 , 3 ⋅ c n t 2 f_{i,2}=f_{i-1,1}\\cdot cnt_2+f_{i-1,3}\\cdot cnt_2 fi,2=fi−1,1⋅cnt2+fi−1,3⋅cnt2
f i , 3 = f i − 1 , 2 ⋅ c n t 3 + f i − 1 , 4 ⋅ c n t 3 f_{i,3}=f_{i-1,2}\\cdot cnt_3+f_{i-1,4}\\cdot cnt_3 fi,3=fi−1,2⋅cnt3+fi−1,4⋅cnt3
f i , 4 = f i − 1 , 2 ⋅ c n t 4 + f i − 1 , 4 ⋅ c n t 4 f_{i,4}=f_{i-1,2}\\cdot cnt_4+f_{i-1,4}\\cdot cnt_4 fi,4=fi−1,2⋅cnt4+fi−1,4⋅cnt4
只需做 L L L 次 dp 即可,但是 L L L 最大去到 1 0 9 10\^9 109,显然会炸。由于操作单调,因此考虑矩阵快速幂优化:
\[ f i , 1 f i , 2 f i , 3 f i , 4 \] = \[ f i − 1 , 1 f i − 1 , 2 f i − 1 , 3 f i − 1 , 4 \] ⋅ \[ c n t 1 c n t 2 0 0 0 0 c n t 3 c n t 4 c n t 1 c n t 2 0 0 0 0 c n t 3 c n t 3 \] \\begin{bmatrix} f_{i,1} \& f_{i,2} \& f_{i,3} \& f_{i,4} \\end{bmatrix}=\\begin{bmatrix} f_{i-1,1} \& f_{i-1,2} \& f_{i-1,3} \& f_{i-1,4} \\end{bmatrix}\\cdot\\begin{bmatrix} cnt_1 \& cnt_2 \& 0 \& 0\\\\ 0 \& 0 \& cnt_3 \& cnt_4\\\\ cnt_1 \& cnt_2 \& 0 \& 0\\\\ 0 \& 0 \& cnt_3 \& cnt_3 \\end{bmatrix} \[fi,1fi,2fi,3fi,4\]=\[fi−1,1fi−1,2fi−1,3fi−1,4\]⋅ cnt10cnt10cnt20cnt200cnt30cnt30cnt40cnt3
### 代码
```cpp
#include
中括号为艾弗森括号,不难发现 A A A 以对角线对称。
对于每个 ( i , j ) (i,j) (i,j),都要遍历 k ∈ [ 1 , n ] k\in[1,n] k∈[1,n] 来逐一比对一遍是否有 a j ⨁ a k m o d 3 = 0 a_j\bigoplus a_k \bmod3=0 aj⨁akmod3=0。如此过程,实则与矩阵乘法的运算过程比较相似(这还是比较注意力惊人了,除非你对矩阵无比的熟悉)那么不妨使用矩阵快速幂优化了。最终答案就是:
a n s = ∑ d a t a ( A n − 1 ) ans=\sum data(A^{n-1}) ans=∑data(An−1)
d a t a ( M ) data(M) data(M) 表示一个矩阵 M M M 内所有元素。
cpp
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=102,mod=1e9+7;
struct matrix
{
ll row,col;
ll data[N][N];
matrix(ll r,ll c,ll isI)
{
row=r;
col=c;
memset(data,0,sizeof(data));
if(isI)
{
for(int i=1;i<=row;i++)
data[i][i]=1;
}
}
};
matrix operator * (const matrix &a,const matrix &b)
{
matrix c(a.row,b.col,0);
for(int i=1;i<=a.row;i++)
for(int j=1;j<=b.col;j++)
for(int k=1;k<=a.col;k++)
c.data[i][j]=(c.data[i][j]+a.data[i][k]*b.data[k][j]%mod+mod)%mod;
return c;
}
matrix qpow_matrix(matrix a,ll k)
{
matrix ret(a.row,a.col,1);
while(k)
{
if(k&1)ret=ret*a;
a=a*a;
k>>=1;
}
return ret;
}
ll n,m,a[N];
ll popcnt(ll x)
{
ll ret=0;
while(x)
{
if(x&1)ret++;
x>>=1;
}
return ret;
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
matrix A(n,n,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
A.data[i][j]=(popcnt(a[i]^a[j])%3==0);
A=qpow_matrix(A,m-1);
ll ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
ans=(ans+A.data[i][j])%mod;
printf("%lld",ans);
return 0;
}
6.SMOJ 黑板与数字/CF621E Wet Shark and Blocks
(本篇较口胡,见谅)
题意
有 b b b 个黑板,从左往右排成一行。
第 1 1 1 个黑板从左往右写有 n n n 个数字,每个数字是 1 1 1 至 9 9 9 范围内的数字。
把第 1 1 1 个黑板的所有数字复制一份,写到第 2 2 2 个黑板。
把第 1 1 1 个黑板的所有数字复制一份,写到第 3 3 3 个黑板。
把第 1 1 1 个黑板的所有数字复制一份,写到第 b b b 个黑板。
从这 b b b 个黑板中,各取一个数字,构成一个 b b b 位数,要使得这个 b b b 位数模 x x x 的结果是 k k k,求方案数(同一个黑板内取相同的数字算不同方案,因为位置不同),答案模 1 0 9 + 7 10^9+7 109+7。
思路
令 f i , j f_{i,j} fi,j 表示选了 i i i 个格子,模 x x x 余数为 j j j,那么有转移式子:
f i , 10 j + k m o d x = f i − 1 , j + n u m ( k ) f_{i,10j+k \bmod x}=f_{i-1,j}+num(k) fi,10j+kmodx=fi−1,j+num(k)
其中 n u m ( k ) num(k) num(k) 表示: n u m ( k ) = ∑ i = 1 n [ a i m o d x = k ] num(k)=\sum_{i=1}^n [a_i\bmod x=k] num(k)=i=1∑n[aimodx=k]
再枚举每一位,去到了 Θ ( b x ) \Theta(bx) Θ(bx);但是如此操作,像上几篇题解一样,与矩阵乘法相类似,因此可以考虑矩阵快速幂优化到 Θ ( log 2 b ) \Theta(\log_2b) Θ(log2b)
代码
cpp
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=111,mod=1e9+7;
ll n,b,k,x,a,yx[N];
struct matrix
{
ll row,col;//行和列
ll data[N][N];
matrix(ll r,ll c,ll isI)
{
row=r;
col=c;
memset(data,0,sizeof(data));
if(isI)
{
for(int i=0;i<row;i++)
data[i][i]=1;
}
}
};
matrix operator * (const matrix &a,const matrix &b)
{
matrix c(a.row,b.col,0);
for(int i=0;i<a.row;i++)
for(int j=0;j<b.col;j++)
for(int k=0;k<a.col;k++)
c.data[i][j]=(c.data[i][j]+a.data[i][k]*b.data[k][j]%mod+mod)%mod;
return c;
}
matrix qpow_matrix(matrix a,ll k)
{
matrix res(a.row,a.col,1);
while(k)
{
if(k&1)res=res*a;
a=a*a;
k>>=1;
}
return res;
}
int main()
{
scanf("%lld%lld%lld%lld",&n,&b,&k,&x);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a);
yx[a%x]++;
}
matrix A(1,x,0);
for(int i=0;i<x;i++)
A.data[0][i]=yx[i];
matrix B(x,x,0);
for(int i=0;i<x;i++)
{
for(int j=0;j<x;j++)
{
ll r=(i*10+j)%x;
B.data[i][r]+=yx[j];
}
}
A=A*qpow_matrix(B,b-1);
printf("%lld",A.data[0][k]);
return 0;
}