zoukankan      html  css  js  c++  java
  • BZOJ2339: [HNOI2011]卡农(dp 容斥)

    题意

    从$1 - n$中任意选择一些数,选$m$次构成$m$个集合

    保证:

    • 集合不为空
    • 任意两个集合不相同
    • 集合内各个元素xor起来等于0

    Sol

    神仙题Orz

    我看到两种做法,一种是洛谷题解上的直接dp,另一种是yyb的神仙转化。

    其实都差不多吧。。

    我简单说一下,设$f[i]$表示选了$i$个集合,满足条件的方案

    直接转移会非常麻烦,因为要同时限制集合不同 xor不为0,我们又不知道集合的具体元素。

    因此我们考虑容斥。

    为了方便考虑,我们先不考虑每个元素的位置,最后再除以$M!$

    因为xor的性质,若我们已经知道了前$i - 1$个元素,那么我们这时候选什么是确定的。

    先确定出前$i - 1$个数,方案数为$A_{2^n - 1}^{i - 1}$,

    考虑若此时选了一个空的集合,那我们要保证前$i - 1$个集合满足条件,方案数为$f[i - 1]$

    若选了重复的集合(这是最难理清楚的),剩下的$i - 2$个元素很定要满足条件,方案数为$f[i - 2]$,然后我们枚举一个集合,方案数为$2^{n} - (i - 2)$,这样看似就可以了。但是我们在递推的时候是没有考虑顺序的,因此另一个元素有$i - 1$种取值,因此还要乘$i - 1$

    得到递推式

    f[i]=A_{2^n-1}^{i-1}-f[i-1]-(i-1) imes f[i-2] imes(2^n-1-(i-2))

    // luogu-judger-enable-o2
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<stack>
    #include<vector>
    #include<cstring>
    #define LL long long 
    //#define int long long
    using namespace std;
    const int MAXN = 3 * 1e6;
    const LL mod = 1e8 + 7;//fuck
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N, M;
    LL ifac[MAXN], fac[MAXN], f[MAXN], A[MAXN];
    LL fastpow(LL a, LL p) {
        LL base = 1;
        while(p) {
            if(p & 1) base = (base * a) % mod;
            a = (a * a) % mod; p >>= 1;
        }
        return base % mod;
    }
    main() {
        N = read(); M = read(); LL base = fastpow(2, N) % mod;
        fac[0] = A[0] = 1; for(int i = 1; i <= M; i++) fac[i] = 1ll * i * fac[i - 1] % mod;
        ifac[M] = fastpow(fac[M], mod - 2);
        for(int i = 1; i <= M; i++) A[i] = 1ll * A[i - 1] * (base - i + mod) % mod;
        f[0] = 1; f[1] = 0; 
        for(int i = 2; i <= M; i++) f[i] = ((A[i - 1] - f[i - 1] + mod) % mod - 1ll * f[i - 2] * (i - 1) % mod * (base - i + 1) % mod + mod) % mod;
        printf("%lld", f[M] * ifac[M] % mod);
        return 0;
    }
    /*
    99999 99999
    */
  • 相关阅读:
    FreeSql.Repository (九)级联保存
    FreeSql.Repository (八)级联加载
    FreeSql.Repository (七)多表查询
    FreeSql.Repository (六)导航属性
    FreeSql.Repository (五)状态管理
    FreeSql.Repository (四)工作单元
    FreeSql.Repository (三)实体特性
    FreeSql.Repository (一)什么是仓储
    [开源] .Net 使用 ORM 访问 华为GaussDB数据库
    24位PCM采样数据转成16位算法,已实现PCM转WAV在线工具源码支持24bits、16bits、8bits
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/9540625.html
Copyright © 2011-2022 走看看