题目描述
Lh:粉兔你教我一下抽屉原理吧
Clz:就是给你一个长度为 n 的序列,每个数只能取 0,1,2,那你连续取三个数必然有两个相等……
Lh:等等你梭啥,再说一遍
Clz:……emmm 当我没说
Marser:就是一个序列,对于每一个连续三元组都要满足其中至少有两个相等
现在粉兔问你:有多少个长度为 n 的序列满足粉兔的要求?请对 19260817 取模。输入
一行一个正整数n(3≤n≤1018)。
输出
一行一个整数,含义如题。
样例输入 Copy
4样例输出 Copy
51
思路:
令f[n]为长度为n的合法序列数量
假设序列 s-1的末尾两个数相同则s有三种选法,如果不同有两种选法。
s-1末尾相同的选法可以由f[s-2]表示.则f[n]=2*f[n-1]+f[n-2]
想这种类似斐波拉且的递推是,可以用矩阵快速幂优化。
Code:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<unordered_map>
using namespace std;
#define x first
#define y second
#define PII pair<int,int>
#define V vector<int>
#define endl "\n"
typedef long long ll;
typedef unsigned long long llu;
const int INF=0x3f3f3f3f,mod=19260817;
struct matrix
{
ll mat[2][2];
void init() {
memset(mat,0,sizeof mat);
}
};
matrix mul(matrix a,matrix b)
{
matrix c;
c.init();
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
for(int k=0;k<2;k++) {
c.mat[i][j]+=(a.mat[i][k]%mod)*(b.mat[k][j]%mod)%mod;
c.mat[i][j]%=mod;
}
}
}
return c;
}
matrix ksm(matrix a,ll n)
{
matrix b;
b.init();
for(int i=0;i<2;i++) b.mat[i][i]=1;
while(n)
{
if(n&1) b=mul(b,a);
a=mul(a,a);
n>>=1;
}
return b;
}
int main()
{
//f[n]=2*f[n-1]+f[n-2]
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
ll n;
cin>>n;
if(n==3) cout<<21;
else if(n==4) cout<<51;
else
{
matrix a,res,ans;
a.mat[0][0]=2;
a.mat[0][1]=a.mat[1][0]=1;
a.mat[1][1]=0;
res=ksm(a,n-4);
ans.init();
ans.mat[0][0]=51;
ans.mat[0][1]=21;
ans=mul(ans,res);
cout<<ans.mat[0][0];
}
return 0;
}
形如:f[n]=a*f[n-1]+b*f[n-2]+c
可用矩阵乘积形式表示
=
形如:f[n]=c^n-f[n-1]
=