题目链接:http://acm.uestc.edu.cn/#/problem/show/1610
解法:
卿式扑克序列?
出现一组有连续4张牌均不同的序列
不好计算,怎么办?
可以计算出没有一组连续4张牌均不同的情况,用总情况减去没有一组连续4张牌均不同的情况
我们来看 三张牌排成一排有哪些情况?
三张牌均相同 AAA dp1
前两张牌相同,第三张牌不同 AAB dp2
第一和第三张牌相同,第二张牌不同 ABA dp3
后两张牌相同,第一张牌不同 BAA dp4
三张牌均不相同 ABC dp5
我们设dpx[i]为前i张牌最后三张牌为第x种类型且不出现一组连续4张牌均不同的情况
可得以下方程:
dp1[i]=dp1[i-1]+dp4[i-1]
dp2[i]=3*dp1[i-1]+3*dp4[i-1]
dp3[i]=dp2[i-1]+dp3[i-1]+dp5[i-1]
dp4[i]=dp2[i-1]+dp3[i-1]+dp5[i-1]
dp5[i]=2*dp2[i-1]+2*dp3[i-1]+dp5[i-1]
初始值:dp1[3]=4 dp2[3]=12 dp3[3]=12 dp4[3]=12 dp5[3]=24
N=10^18 逗我呢?
矩阵快速幂!
(dp1[i],dp2[i],dp3[i],dp4[i],dp5[i])=(dp1[i-1],dp2[i-1],dp3[i-1],dp4[i-1],dp5[i-1])*
B(N)=B(3)*A^(N-3)
Matrix multiply(Matrix a,Matrix b) {}
void quickmat(long long k)
{
while(k)
{
if (k & 1) {res=multiply(res,origin);}
k>>=1;
origin=multiply(origin,origin);
}
}
res=dp1[n]+dp2[n]+dp3[n]+dp4[n]+dp5[n]
用普通快速幂算出4^n=tot,本题所求的答案ans=tot-res;注意取模的问题
算法复杂度:O(log N)
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 1e9+9;
LL powmod(LL a, LL n)
{
LL res=1;
while(n){
if(n&1) res=(res%mod*a%mod)%mod;
a=(a%mod*a%mod)%mod;
n>>=1;
}
return res;
}
struct Matrix{
LL a[5][5];
void init(){
memset(a,0,sizeof(a));
}
void init2(){
memset(a,0,sizeof(a));
for(int i=0; i<5; i++) a[i][i]=1;
}
};
Matrix operator * (Matrix a, Matrix b){
Matrix res;
res.init();
for(int i=0; i<5; i++){
for(int j=0; j<5; j++){
for(int k=0;k<5; k++){
res.a[i][j]=(res.a[i][j]+(a.a[i][k]*b.a[k][j])%mod)%mod;
}
}
}
return res;
}
Matrix ksm(Matrix a, LL n){
Matrix res;
res.init2();
while(n){
if(n&1) res=res*a;
a=a*a;
n>>=1;
}
return res;
}
int main()
{
LL n;
scanf("%lld",&n);
Matrix A,B;
A.init();
B.init();
A.a[0][0]=1,A.a[0][1]=3,A.a[1][2]=1,A.a[1][3]=1,A.a[1][4]=2;
A.a[2][2]=1;A.a[2][3]=1;A.a[2][4]=2;
A.a[3][0]=1;A.a[3][1]=3;
A.a[4][2]=1;A.a[4][3]=1;A.a[4][4]=1;
B.a[0][0]=4;B.a[0][1]=12;B.a[0][2]=12;B.a[0][3]=12;B.a[0][4]=24;
Matrix ans=ksm(A,n-3);
// for(int i=0; i<5; i++){
// for(int j=0; j<5; j++){
// printf("%d ",ans.a[i][j]);
// }
// printf("\n");
// }
ans=B*ans;
// for(int i=0; i<5; i++){
// for(int j=0; j<5; j++){
// printf("%d ",ans.a[i][j]);
// }
// printf("\n");
// }
LL ret = 0;
for(int i=0; i<5; i++){
ret=(ret+ans.a[0][i])%mod;
}
ret = (powmod(4,n)-ret+mod)%mod;
if(ret<0) ret+=mod;
printf("%lld\n", ret);
return 0;
}