zoukankan      html  css  js  c++  java
  • [HNOI 2012]集合选数

    Description

    题库链接

    对于任意一个正整数 (n) ,求出集合 ({1,2,cdots,n}) 的满足约束条件“若 (x) 在该子集中,则 (2x)(3x) 不能在该子集中”的子集的个数。

    (nleq 100000)

    Solution

    容易发现对于每一个与 (2,3) 互质的数 (k) ,我们构造一个 (p imes q) 的矩阵,该矩阵的第 (i) 行第 (j) 列表示数值 (kcdot 2^i3^j) 。由于数值要 (leq n) ,所以这个矩阵不是完整的。

    显然对于这个矩阵,我选取的数不能相邻,由于 (p,q) 很小,可以用状压 (DP) 实现,来计算总方案数。

    同样对于每个这样的 (k) 。可以随意组合所以将方案数乘起来就好了。

    Code

    //It is made by Awson on 2018.3.9
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int yzh = 1000000001, N = 200000;
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int n, ans = 1, bin[20], f[20][N+5];
    
    void work() {
        read(n); bin[0] = 1; for (int i = 1; i <= 19; i++) bin[i] = bin[i-1]<<1;
        for (int id = 1; id <= n; id++)
        if (id%2 && id%3) {
            int last = 0, now, tmp = id, k; f[0][0] = 1;
            for (k = 1; tmp <= n; k++) {
            for (now = 0; now <= 19; now++) if (tmp*bin[now] > n) break;
            for (int i = 0; i < bin[now]; i++)
                if ((i&(i>>1)) == 0) {
                f[k][i] = 0;
                for (int j = 0; j < bin[last]; j++)
                    if ((i&j) == 0 && (j&(j>>1)) == 0)
                    f[k][i] = (f[k][i]+f[k-1][j])%yzh;
                }
            last = now, tmp *= 3;
            }
            int t = 0;
            for (int i = 0; i < bin[last]; i++) if ((i&(i>>1)) == 0) t = (t+f[k-1][i])%yzh;
            ans = 1ll*ans*t%yzh;
        }
        writeln(ans);
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    maven-scm-plugin: Add a tag into Mercurial. 在Mercurial中添加一个tag
    JSch
    docker-compose install
    如何删除Dead状态的container
    inux下如何添加一个用户并且让用户获得root权限
    Log4j2 自定义 Appender
    Harbor私有镜像仓库(上)
    docker基础(下)
    docker基础(上)
    Pipeline流水线JAVA项目发布
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8533787.html
Copyright © 2011-2022 走看看