[ DP ] [ HNOI2012 ] BZOJ2734

考虑这样一个矩阵:

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值