考虑这样一个矩阵:
1 3 9 27
2 6 18 54
4 12 36 108
那么问题就变成了在这个矩阵中选几个数,相邻的数不能选。
由于列数最多只有
11
11
,可以状压DP 。
然后发现有些数不在这个矩阵中。再将这些数分别作为矩阵左上角做一遍,由于矩阵间互不影响,将答案乘起来就好了。
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
const int M=1000000001;
int k,n,m;
int len;
int f[20][N<<1];
int p[20];
int a[20];
int Ans=1;
bool b[N];
inline void Add(int& x,int y){
x=(x+y)%M;
}
inline int Calc(int x){
for(int i=1,t=x;;i++,t<<=1){
if(t>n){
len=i-1;
break;
}
for(int j=1,tmp=t;;j++,tmp*=3){
if(tmp>n){
a[i]=j-1;
break;
}
b[tmp]=1;
}
}
for(int i=1;i<=len;i++)
for(int j=0;j<p[a[i]];j++)f[i][j]=0;
f[0][0]=1;
for(int i=1;i<=len;i++){
for(int j=0;j<p[a[i-1]];j++)
if(f[i-1][j])
for(int k=0;k<p[a[i]];k++)
if(!(k&(k>>1))&&!(k&j))
Add(f[i][k],f[i-1][j]);
}
int Ans=0;
for(int i=0;i<p[a[len]];i++)Add(Ans,f[len][i]);
return Ans;
}
int main(){
scanf("%d",&n);
p[0]=1;
for(int i=1;i<20;i++)p[i]=p[i-1]<<1;
for(int i=1;i<=n;i++)
if(!b[i])Ans=1ll*Ans*Calc(i)%M;
cout<<Ans<<endl;
return 0;
}