解析
做法闻所未闻的神仙题。
题目可以看成求这张特殊图的合法独立集数目。
这张图有一个特点:链长是
O
(
log
n
)
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_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=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