• HNOI2011 卡农


    题目传送门

    Description

    (n​)种元素,构成(m​)个集合((n,mleq 10^6)),保证集合互不相同且非空,且每个元素总出现次数为偶数,两种方案集合重新排列可互相得到算一种,求方案数。

    Solution

    开始做的时候不用管重新排列算重,只要最后除以(m!)即可。

    (f_i)(i​)个子集的答案。

    因为出现次数为偶数,所以确定前(i-1)个子集后,第(i)个也唯一确定。即选择(i-1)个子集的方案数,总共有(2^n-1)个子集,所以为(A_{2^n-2}^{i-1})

    然后有一些方案不符合要求,需要删去。

    若第(i)个集合为空,那么前(i-1)个为一种合法方案,所以要减去(f_{i-1})

    若第(i​)个集合与第(j(j<i)​)个集合相同,那么剩下(n-2​)个集合为一种合法方案(f_{n-2}​)(j​)的位置有(n-1​)种取值,而当(n-2​)中确定后,(i​)(j​)的取法为(2^n-1-(n-2)​)。所以需减去(f_{i-2}cdot (i-1)cdot (2^n-i+1)​)

    综上所述:

    [f_i=A_{2^n-1}^{i-1}-f_{i-1}-f_{i-2}cdot (i-1)cdot (2^n-i+1) ]

    [Ans=frac{f_m}{m!} ]

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1000005, P=100000007;
    int A[N], F[N];
    
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
        for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
        return x*f;
    }
    
    int Pow(int x, int t)
    {
        int res=1;
        while (t) t&1?res=1ll*res*x%P:0, x=1ll*x*x%P, t>>=1;
        return res;
    }
    
    int main()
    {
        int n=read(), m=read(), t=Pow(2, n), p=1; A[0]=1; F[F[1]=0]=1;
        for (int i=1; i<=m; i++) A[i]=1ll*A[i-1]*(t-i)%P, p=1ll*p*i%P;
        for (int i=2; i<=m; i++) F[i]=(A[i-1]-F[i-1]-1ll*F[i-2]*(i-1)%P*(t-i+1)%P)%P;
        printf("%d
    ", ((1ll*F[m]*Pow(p, P-2)%P)+P)%P);
        return 0;
    }
    
    
  • 相关阅读:
    HTTP协议
    C# 调用接口实例httpclient(postman)
    什么是Web Service?什么是soap?
    windows服务启动失败解决流程(1053错误举例)
    C# 创建window服务 -- 定时任务
    自定义Log日志
    C# 调用web service soap接口(wsdl文件)(一) --- 接口请求
    C# List转Json,Json转List
    MVC+EF+SQL Server项目创建数据库连接流程
    查询库中所有的表及表中记录总条数
  • 原文地址:https://www.cnblogs.com/ACMSN/p/10742980.html
Copyright © 2020-2023  润新知