As we all know,every coin has two sides,with one side facing up and another side facing down.Now,We consider two coins's state is same if they both facing up or down.If we have N coins and put them in a line,all of us know that it will be 2^N different ways.We call a "N coins sequence" as a Lucky Coins Sequence only if there exists more than two continuous coins's state are same.How many different Lucky Coins Sequences exist?
3 4
2 6
转载(看到一篇博客分析不错,就不自己写啦 )
咋一看还以为是DP,当看到规模的时候傻眼了,10^9!!!!!这下咋办…
后来才知道是要推公式的,问了两位大牛,公式是这么推的:
长度为n的01串一共有2^n种不同的排列方法,
设f(n)为长度是n的不包含连续3个或以上相同的1或0的01串,
则f(1)=2,f(2)=4,f(3)=6,f(4)=10
当n>4的时候,分情况考虑:
1、 如果是以00或者11结尾,则分别有f(n-2)/2种情况,加起来就是f(n-2)种.
2、 如果是以01或者10结尾,则第n个字符要和第n-1个字符不一样,那么分别有f(n-1)/2种,加起来就是f(n-1)
则统计起来就是f(n)=f(n-1)+f(n-2),题目要求的是包含连续三个相同的0或1串的串数,那就是用a[n]=(2^n-f(n))%10007.
然而这样还不好求,先不看%10007,转换成递推公式是a[n]=a[n-1]+a[n-2]+2^(n-2),
转换成矩阵:
a[n] 1 1 1 a[n-1]
a[n-1] = 1 0 0 * a[n-2]
2^(n-1) 0 0 2 2^(n-2)
这样就可以用矩阵幂快速算出a[n],复杂度为O(logn)
代码原创
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=10007;
int x[4][4],ret[4][2],t[4][4];
void f1()
{
memset(t,0,sizeof(t));
for(int i=1;i<=3;i++)
for(int k=1;k<=3;k++)
t[i][1]=(t[i][1]+x[i][k]*ret[k][1])%N;;
for(int i=1;i<=3;i++)
ret[i][1]=t[i][1];
}
void f2()
{
memset(t,0,sizeof(t));
for(int i=1;i<=3;i++)
for(int k=1;k<=3;k++)
for(int j=1;j<=3;j++)
t[i][j]=(t[i][j]+x[i][k]*x[k][j])%N;
for(int i=1;i<=3;i++)
for(int j=1;j<=3;j++)
x[i][j]=t[i][j];
}
int main()
{
int a[5]={0,0,0,2,6};
int m;
while(scanf("%d",&m)!=EOF)
{
if(m<=4){printf("%d\n",a[m]);continue;}
m-=4;
x[1][1]=x[1][2]=x[1][3]=x[2][1]=1;
x[2][2]=x[2][3]=x[3][1]=x[3][2]=0;
x[3][3]=2;
ret[1][1]=6,ret[2][1]=2;ret[3][1]=8;
while(m>0)
{
if(m&1)f1();
f2();
m=m/2;
}
printf("%d\n",ret[1][1]);
}
return 0;
}