zoukankan      html  css  js  c++  java
  • 题解 P3214 【[HNOI2011]卡农】

    简化题面:

    从集合{(1,2,3....n)}中选择(m)个互不相同的非空集合且所有元素出现次数为偶数的方案数。

    解题思路:

    因为对于集合位置不同的方案数算1,因此我们考虑像全排列变组合数一样对无序的方案数除以(m!)就是我们所要的答案。

    第一眼看上去像是第二类斯特林数?但是仔细一看并不是。考虑是(dp[i])为选(i)个集合并且满足限制条件的有序方案数。

    直接求很困难因此考虑容斥,总方案减不合法方案就是最后的答案

    考虑总方案是什么,由于限制元素所有元素出现次数必须为偶数,因此对于(i)是确定的,因此总方案为(2^n-1)的集合(注意这里舍去了空集)中选取(i-1)的排列(A_{2^n-1}^{i-1})

    对于不合法的方案我们考虑两种情况

    1,前(i-1)个集合合法但第(i)个为空集,因此还是(dp[i-1])

    2,前(i-1)个集合合法第(i)个集合和前面相同,因此我们要将两个重复的集合都删去,即为(dp[i-2] imes (i-1) imes (2^n-1-(i-2)))

    那么对于(dp[i])我们就有了递推式(dp[i]=A_{2^n-1}^{i-1}-dp[i-1]-dp[i-2] imes (i-1) imes (2^n-1-(i-2)))

    最后答案除以(m!)即可

    Code

    #include<bits/stdc++.h>
        
    #define LL long long
        
    #define _ 0
        
    using namespace std;
        
    /*Grievous Lady*/
        
    template <typename _n_> void mian(_n_ & _x_){
        _x_ = 0;int _m_ = 1;char buf_ = getchar();
        while(buf_ < '0' || buf_ > '9'){if(buf_ == '-')_m_ =- 1;buf_ = getchar();}
        do{_x_ = _x_ * 10 + buf_ - '0';buf_ = getchar();}while(buf_ >= '0' && buf_ <= '9');_x_ *= _m_;
    }
        
    const int kato = 1e6 + 10;
    
    #define mod 100000007
    
    inline LL quick_pow(LL a , LL b){
        LL res = 1;
        for(; b ; b >>= 1 , a = a * a % mod){
            if(b & 1){
                res = res * a % mod;
            }
        }
        return res % mod;
    }
    
    LL n , m , fac = 1;
    
    LL A[kato] , dp[kato];
    
    inline int Ame_(){
        mian(n) , mian(m);
        int poi = quick_pow(2 , n) - 1;
        A[0] = 1;
        dp[0] = 1 , dp[1] = 0;
        for(int i = 1;i <= m;i ++){
            A[i] = (A[i - 1] * ((poi - i + 1 + mod) % mod)) % mod;
        }
        for(int i = 2;i <= m;i ++){
            dp[i] = (A[i - 1] - dp[i - 1] - dp[i - 2] * (i - 1) % mod * (poi - i + 2 + mod) % mod + mod) % mod;
        }
        for(int i = 2;i <= m;i ++){
            fac = fac * i % mod;
        }
        printf("%lld
    " , dp[m] * quick_pow(fac , mod - 2) % mod);
        return ~~(0^_^0);
    }
        
    int Ame__ = Ame_();
        
    int main(){;}
    

    -----(egin{aligned}mathcal{Ame}end{aligned})__

  • 相关阅读:
    ByteArrayInputStream(字节数组输入流) 示例
    ASP.NET 页面对象模型
    HTML常用标记
    [elementui]上线iconfont乱码
    time与timeEnd测试运行时间
    放大镜效果
    canvas
    [css] 样式列表
    千分符
    centos源失败
  • 原文地址:https://www.cnblogs.com/Ame-sora/p/13639652.html
Copyright © 2011-2022 走看看