解析
做法闻所未闻的神仙题。
题目可以看成求这张特殊图的合法独立集数目。
这张图有一个特点:链长是 O(logn)O(\log n)O(logn) 级别的,且每个点的度数比较少。
考虑构造如下矩阵:
1 3 9 12 ...
2 6 18 54 ...
4 ...
8 ...
这个矩阵其实就是对这张图的一个联通块具象表达。
由于长宽都是 log 级别,直接状压即可。
然后把所有的连通块都提出来算出答案乘起来即所求。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;const int N=2e5+100;
const int mod=1e9+1;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}inline ll ksm(ll x,ll k){ll res(1);while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}
int n;
int x[105][105],mi[50],len[50],h,vis[N];
int f[25][N];
ll ans=1;
void work(int o){x[1][1]=o;h=1;while(o*2<=n){o<<=1;x[++h][1]=o;}for(int i=1;i<=h;i++){len[i]=1;while(x[i][len[i]]*3<=n){x[i][len[i]+1]=x[i][len[i]]*3;len[i]++;}for(int j=1;j<=len[i];j++) vis[x[i][j]]=1;for(int j=0;j<mi[len[i]];j++) f[i][j]=0;//for(int j=1;j<=len[i];j++) printf("%d ",x[i][j]);// puts("");}f[0][0]=1;ll res(0);for(int i=0;i<h;i++){for(int s=0;s<mi[len[i]];s++){if(s&(s<<1)) continue;//printf("i=%d s=%d f=%d\n",i,s,f[i][s]);for(int t=0;t<mi[len[i+1]];t++){if(s&t) continue;if(t&(t<<1)) continue;//printf(" -> t=%d\n",t);(f[i+1][t]+=f[i][s])%=mod;}}}for(int s=0;s<mi[len[h]];s++){//printf("i=%d s=%d f=%d\n",h,s,f[h][s]);(res+=f[h][s])%=mod;}ans=ans*res%mod;return;
}signed main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifn=read();mi[0]=1;for(int i=1;i<=20;i++) mi[i]=mi[i-1]<<1;for(int i=1;i<=n;i++){if(!vis[i]) work(i);}printf("%lld\n",ans);return 0;
}
//288 125 189 111 229