bzoj 2734 集合选数
2015-11-16 10:40
309 查看
构造矩阵1 3 9 27…2 6 18 54…4 12 36 108………每个数是上面的数乘2,左面的数乘3。这样进行状压dp就是相邻的格子不能选的方案数。如何判断一个二进制数没有两个连续的1? x&(x<<1)=0如果有的数没有出现过,就以它为左上角元素再构造一个矩阵。这是怎么想到的?!!
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define ll long long #define inf 1e9 #define eps 1e-10 #define md 1000000001 #define N using namespace std; int a[20][15],b[20],mi[20]; ll f[20][5010]; bool vis[100010]; int n; ll ans=1; void add(ll &x,ll y) { x=x+y; if (x>=md) x-=md; } void solve(int x) { for (int i=1,now=x;i<=18;i++,now*=2) { if (now<=n) { a[i][1]=now; vis[now]=1; b[i]=mi[1]; } else { a[i][1]=n+1; b[i]=0; now=n+1; } } for (int i=1;i<=18;i++) for (int j=2;j<=11;j++) { int x=a[i][j-1]*3; if (x<=n) { a[i][j]=x; vis[x]=1; b[i]+=mi[j]; } else { a[i][j]=n+1; } } for (int i=1;i<=18;i++) for (int j=0;j<=b[i];j++) f[i][j]=0; b[0]=1; f[0][0]=1; for (int i=0;i<18;i++) { for (int j=0;j<=b[i];j++) if (f[i][j]) { for (int k=0;k<=b[i+1];k++) if ( (!(k&(k<<1))) && (!(j&k))) add(f[i+1][k],f[i][j]); } } ans=ans*f[18][0]%md; } int main() { mi[1]=1; for (int i=2;i<=18;i++) mi[i]=mi[i-1]<<1; ans=1; scanf("%d",&n); for (int i=1;i<=n;i++) if (!vis[i]) solve(i); printf("%lld\n",ans); return 0; }
相关文章推荐
- bzoj 2054 疯狂的馒头
- bzoj 2121 字符串游戏
- bzoj 1049 数字序列
- bzoj 2669 局部极小值
- bzoj 3743 kmap
- dp专题训练
- bzoj 1060 时态同步 水题?神题?
- 练贪心!贪心!贪心!
- bzoj 3175 攻击装置 | 二分图最大独立集
- 图解javascript this指向什么?
- 远程控制电脑
- Linux Basics command
- java http 请求方法
- .ajax设置成同步的应用场景
- java泛型编程
- linux下apache2两种工作模式及两者切换
- bzoj 3032 七夕祭 | 中位数
- bzoj 2594 水管局长 | LCT | 最小生成树
- bzoj 3706 反色刷 | 一笔画
- bzoj 3108 图的逆变换