一道不错的套路dp,首先构造矩阵,左上角为最小没有出现的数字,然后向右*3向下*2,这样只要不选相邻的数字就可以了,然后发现矩阵式log级的,状压dp莽一波。
最开始写出来10s卡过,后来看了一下被人的优化:
1.对于每一行预处理出合法的状态用flag标记
2.构造新的矩阵做dp的时候每一行一行的memset,不要一次直接写完(特别坑),否则会重复赋值很多用不上的空间
#include<cstdio>
#include<cstring>
#include<iostream>
#define LL long long
#define maxn 100020
#define Mod 1000000001
using namespace std;
bool vis[maxn],flag[1<<12];
int n,cnt[22];LL f[22][1<<12];
LL solve(int x){
LL ans=0;int p=0;
f[0][0]=1;
while(x<=n){
cnt[++p]=0;int tmp=x;
memset(f[p],0,sizeof(f[p]));
while(tmp<=n){cnt[p]++,vis[tmp]=true;tmp*=3;}
for(int i=0;i< 1<<cnt[p];i++)if(flag[i]){
for(int j=0;j< 1<<cnt[p-1];j++)if(flag[j]&&!(j&i))
f[p][i]=(f[p][i]+f[p-1][j])%Mod;
}
x*=2;
}
for(int i=0;i< 1<<cnt[p];i++)if(flag[i])ans=(ans+f[p][i])%Mod;
return ans;
}
int main(){
scanf("%d",&n);LL ans=1;
for(int i=0;i<1<<12;i++)
if(!(i<<1&i))flag[i]=true;
for(int i=1;i<=n;i++)if(!vis[i])ans=ans*solve(i)%Mod;
printf("%lld",ans);
return 0;
}