zoukankan      html  css  js  c++  java
  • bzoj 4762: 最小集合

    明天就是ZJOI Day1啦

    恩,实际上很早就写了这一题

    然后回来看的时候发现我怎么不会做了……

    看着代码尝试理解一下我当时在想什么(捂脸

    感觉智商下降的好快QAQ

    6.19魔改:

    好了,我现在终于知道当时我在写些什么了……

    一个AND和为(0)的集合(S)合法,当且仅当它所有大小为(|S - 1|)的集合AND和都不为(0)。

    也就是说有(|S|)个限制,每个限制为某个集合的AND和不为(0)

    如果令(S_{a})为(S)删去(a)这个元素所形成的集合,令(f(S))为(S)集合中所有元素的AND和

    那么答案就是$$sum_{S}[(f(S) = 0) wedge igwedge _{ain S} (f(S_{a}) eq0)]$$

    这玩意是很难直接dp的,因此容斥这些限制

    也就是说要去求补集:求某些限制同时不合法的方案数

    于是有这么一个式子:

    $$[igwedge _{ain S} (f(S_{a}) eq0)]= sum_{S'subseteq S}[igwedge _{ain S'} (f(S_{a})=0)](-1)^{|S'|}$$

    注意到$$[igwedge _{ain S'} (f(S_{a})=0)] = [ ext{OR}_{ain S'}f(S_a) = 0]$$

    也就是如果某些限制同时不满足的话,那么如果把所有对应集合的AND和 按位或起来的和为0

    因此答案就等于$$sum_{S}sum_{S'subseteq S}[(f(S) = 0) wedge ext{OR}_{ain S'}f(S_a) = 0](-1)^{|S'|}$$

    暴力的话枚举集合(S),枚举(S)的子集(S')就可以算贡献了

    如果要DP的话只需要记录(S)的AND和,(S')的( ext{OR}_{ain S'}f(S_a)),对应的贡献的话就可以DP了

    令(f_{i,k,j}) 为 考虑了前(i)个数,前者的值为(k),后者的值为(j)的答案

    若第(i + 1)个数为(d)

    如果不选第(i + 1)个数,则有:(f_{i, k, j} o f_{i + 1, k, j})

    如果(S)中选第(i + 1)个数,但(S')中不选,则有:(f_{i, k, j} o f_{i + 1, k & d, j & d})

    如果(S)中选第(i + 1)个数,且(S')中也选,则有:(-f_{i, k, j} o f_{i + 1, k & d, k | j & d})

    初始状态为(f_{0, 1023, 1023} = 1)

    最终答案(ans = f_{n, 0, 0})

    于是就好了

    #include <bits/stdc++.h>
    #define N 1030
    #define MOD 1000000007
    using namespace std;
    int n;
    int f[2][N][N], tmp;
    void ADD(int &t, int d)
    {
        t += d;
        if (t >= MOD) t -= MOD;
    }
    int main()
    {
        scanf("%d", &n);
        f[0][1023][1023] = 1;
        for (int i = 1; i <= n; ++ i)
        {
            int d;
            scanf("%d", &d); 
            tmp ^= 1;
            for (int j = 0; j < 1024; ++ j)
            {
                for (int k = j; k; k = (k - 1) & j)
                    f[tmp][k][j] = 0;
                f[tmp][0][j] = 0;
            }
             
            for (int j = 0; j < 1024; ++ j)
            {
                for (int k = j; k; k = (k - 1) & j)
                    if (f[!tmp][k][j])
                    {
                        ADD(f[tmp][k][j], f[!tmp][k][j]);
                        ADD(f[tmp][k & d][j & d], f[!tmp][k][j]);
                        ADD(f[tmp][k & d][k | j & d], MOD - f[!tmp][k][j]);
                    }
                ADD(f[tmp][0][j], f[!tmp][0][j]);
                ADD(f[tmp][0][j & d], f[!tmp][0][j]);
                ADD(f[tmp][0][j & d], MOD - f[!tmp][0][j]);
                 
            }
        }
        printf("%d", f[tmp][0][0]);
    }
  • 相关阅读:
    mysql最后一个内容orm
    mysql第五天:
    mysql第二天 数据的增删改查补充及外键
    MYsql 初识
    第二天openc的内容:图片的缩放、旋转、格式转换
    第二个内容第一天 opencv的基本内容:
    第五十七天 bom 的新知识
    第五十六天jQurey的内容新增:
    第五十五天jQery内容的进阶
    windows11 upgrade
  • 原文地址:https://www.cnblogs.com/AwD-/p/6600650.html
Copyright © 2011-2022 走看看