BZOJ 2734 集合选数(状态压缩DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2734

题意:给出一个由1到n的数字组成的集合。定义合法子集为若x在子集中则2x、3x均不能在子集中。求有多少个合法的子集。

思路:

1   3    9

2   6    12

4   12   36

对于上面的矩阵,我们发现就等价于不选相邻数字的方案数。因此枚举每个还没有用到的数字,建立以该数字为左上角的矩阵。接着就是状态压缩DP。

int a[N][N];
i64 f[2][1<<12];
int n,r,c,h[100005];

void init(int x)
{
    r=0,c=0; clr(a,0);
    int p1=x,p2,tempC;
    while(p1<=n)
    {
        tempC=0;
        for(p2=p1;p2<=n;p2*=3) a[r][tempC++]=p2,h[p2]=1;
        upMax(c,tempC);
        r++;
        p1<<=1;
    }
}

int set0(int st,int k)
{
    if(st&(1<<k)) return st^(1<<k);
    return st;
}

int get(int st,int k)
{
    return st&(1<<k);
}

void up(i64 &x,i64 y)
{
    x+=y;
    if(x>=mod) x-=mod;
}

i64 DP()
{
    int pre=0,cur=1,M=1<<c;
    int i,j,k,t;
    FOR0(i,M) f[pre][i]=0;
    f[pre][0]=1;
    FOR0(i,r) FOR0(j,c)
    {
        FOR0(k,M) f[cur][k]=0;
        FOR0(t,M) if(f[pre][t])
        {
            up(f[cur][set0(t,j)],f[pre][t]);
            if(!a[i][j]) continue;
            if(j==0)
            {
                if(!(t&1)) up(f[cur][t|1],f[pre][t]);
            }
            else
            {
                if(!get(t,j)&&!get(t,j-1)) up(f[cur][t|(1<<j)],f[pre][t]);
            }
        }
        swap(pre,cur);
    }
    i64 ans=0;
    FOR0(i,M) up(ans,f[pre][i]);
    return ans;
}

int main()
{
    RD(n);
    i64 ans=1;
    int i;
    FOR1(i,n) if(!h[i])
    {
        init(i);
        ans=ans*DP()%mod;
    }
    PR(ans);
}

BZOJ 2734 集合选数(状态压缩DP),布布扣,bubuko.com

时间: 2024-10-25 19:24:04

BZOJ 2734 集合选数(状态压缩DP)的相关文章

[HNOI2012][BZOJ2734] 集合选数|状态压缩动态规划|思路题

2734: [HNOI2012]集合选数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 708  Solved: 414[Submit][Status][Discuss] Description <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤

BZOJ 2734 集合选数

高妙的算法-- 可以构造出形如: 1  2  4   8   16  32 64 3  6  12  24 48 9  18 36 27 54 的矩阵 相邻的数不能被同时选到 因此 将每一个数构造进矩阵 然后状态压缩dp 根据乘法原理 就可以 得出所有的方案 1 #include <bits/stdc++.h> 2 #define mod 1000000001 3 using namespace std; 4 int n,vis[100010],ans,num[23]; 5 int mps[2

bzoj 2734: [HNOI2012]集合选数 状压DP

2734: [HNOI2012]集合选数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 560  Solved: 321[Submit][Status] Description <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何

【BZOJ-2732】集合选数 状压DP (思路题)

2734: [HNOI2012]集合选数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1070  Solved: 623[Submit][Status][Discuss] Description <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n

[HNOI2012]集合选数 --- 状压DP

[HNOI2012]集合选数 题目描述 <集合论与图论>这门课程有一道作业题,要求同学们求出\({1,2,3,4,5}\)的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中. 同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数, 如何求出\({1,2,3...n}\) 的满足上述约束条件的子集的个数(只需输出对 \(10^{9}+1\) 取模的结果),现在这个问题就交给你了. 输入格式: 只有一行,其中有一个正整数 \(n\) 30

HDU 1565 方格取数(1) (状态压缩DP)

HDU 1565 方格取数(1) (状态压缩DP) ACM 题目地址: HDU 1565 方格取数(1) 题意: 中文. 分析: dp[i][j]表示前i行状态j的最优解. 先预处理出符合条件的数,17000+个(n在20以内). 不过感觉复杂度挺高的会T,但是却能A. 这题的正解应该是最小割,回头补下. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * File: 1565_dp.cpp * Create Date: 2014-09-19 23

BZOJ 1087状态压缩DP

状态压缩DP真心不会写,参考了别人的写法. 先预处理出合理状态, 我们用二进制表示可以放棋子的状态,DP[I][J][K]:表示现在处理到第I行,J:表示第I行的状态,K表示现在为止一共放的棋子数量. #include<stdio.h> #include<iostream> #define N 1111 using namespace std; typedef long long ll; int num,n,m; ll dp[11][1<<11][90]; int hh

Hdu-1565 方格取数(1) (状态压缩dp入门题

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4702    Accepted Submission(s): 1782 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出

POJ2288Islands and Bridges(状态压缩DP,求最大路和走条数)

Islands and Bridges Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 8845   Accepted: 2296 Description Given a map of islands and bridges that connect these islands, a Hamilton path, as we all know, is a path along the bridges such that i