http://acm.hdu.edu.cn/showproblem.php?pid=3519
HDU 3519 Lucky Coins Sequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 215 Accepted Submission(s): 130
Sample Input
3
4
Sample Output
2
6
这类题目的一般步骤:
1、首先找到递推关系式,如f[n]=f[n-1]+f[n-2]+2^(n-2);
2、由递推关系式建立一个矩阵关系式,上面的对应矩阵关系式为:
在写矩阵关系式时,最好包含一个常量矩阵,另外2个矩阵保持对称关系,再由递推关系式确立常量矩阵。
3、建立一个矩阵表 sq[n]=A^(2^n), A为所求得的常量矩阵,sq[][][]为一三维矩阵,sq[0][][]为A^1,sq[1][][]为A^2,sq[2][][]为A^4……
这里用到二分法思想哦~
数据范围为max,则打矩阵sq表log2(max)个。
求一个的矩阵的多少次幂又用到二进制,详细请看源程序吧!
4、求f[n]可由矩阵的乘积得出:
代码:
//题目:http://acm.hdu.edu.cn/showproblem.php?pid=3519
//n个硬币排成一行,正面或反面朝上,总共有2^n中摆法。存在连续的大于等于3枚硬币朝向相同时,这种摆放方式成为幸运序列。给n,求幸运序列的个数
/*
分析:我们设f(n)为不满足条件的个数
若f(n)的后两位相同 则f(n)=f(n-2); 即在f(n-2)后面加上00或者11;
若f(n-1)的后两位不同 则f(n)=f(n-1) 即在f(n-1)后面加上0或者1;
因此可得f(n)=f(n-1)+f(n-2);
设g(n) 为符合的个数 则g(n)=2^n-f(n); 化简成关于g(n)的公式为 g(n)=g(n-1)+g(n-2)+2^(n-2);
*/
#include<iostream>
#include<cstring>
using namespace std;
int sq[35][3][3]={{{1,1,1},{1,0,0},{0,0,2}} };
int main()
{
int n,ans,i,j,k,l;
int m[3][3]={0};
for(l=1;l<32;l++)
for(i=0;i<3;i++)
for(j=0;j<3;j++)
for(k=0;k<3;k++)
sq[l][i][j]=(sq[l][i][j]+sq[l-1][i][k]*sq[l-1][k][j])%10007;
//sq[n]=A^(2^n);
while(cin>>n)
{
if(n==1||n==2||n==0)
{
cout<<0<<endl;continue;
}
if(n==3)
{
cout<<2<<endl;continue;
}
int t[3][3]={{1,0,0},{0,1,0},{0,0,1}};
n=n-3;
l=0;
while(n)
{
if(n&1)
{
memset(m,0,sizeof(m));
for(i=0;i<3;i++)
for(j=0;j<3;j++)
for(k=0;k<3;k++)
m[i][j]=(m[i][j]+t[i][k]*sq[l][k][j])%10007;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
t[i][j]=m[i][j];
}
l++;
n=n>>1;
}
ans=(t[0][0]*2+t[0][2]*4)%10007;
cout<<ans<<endl;
}
return 0;
}