zoukankan      html  css  js  c++  java
  • [HNOI2011]卡农

    题目链接:Click here

    Solution:

    题面讲的我一脸懵,我们先来简化一下题目意思:求在([1,2^n-1])内选择(m)个数使得她们异或和为0的方案数

    直接求是不那么好求的,正难则反,我们考虑通过不合法的方案数来求,设(f[i])表示选了(i)个数的合法排列

    由于要异或和为0,所以事实上我们选了(i-1)个之后,第(i)个就已经确定了,所以总排列数为(A_{2^n-1}^{i-1})

    考虑不合法的情况分成2种:选了0和选了已经重复的

    假如选了0,说明这(i-1)个数异或和为0,则我们需要减去(f[i-1])

    加入我们选了一个重复的,则剩下的(i-2)个异或和为0,我们枚举那个数和位置,则减(f[i-2] imes (2^n-1-(i-2)) imes (i-1))

    即:

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

    最后,答案即为(f[m])除以(m!),那为什么要求排列而不直接求组合呢?

    因为组合数我们是不能(O(m))递推的,而排列数可以,所以我们先求出排列数,再算答案

    Code:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+11;
    const int mod=1e8+7;
    int n,m,A[N],f[N];
    int qpow(int a,int b){
        int re=1;
        while(b){
            if(b&1) re=(re*1ll*a)%mod;
            b>>=1;a=(a*1ll*a)%mod;
        }return re;
    }
    int read(){
        long long x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    signed main(){
        n=read(),m=read();int ifac=1;
        int Val=qpow(2,n);--Val;f[0]=1;A[0]=1;
        if(Val<m) return puts("0"),0;
        for(int i=1;i<=m;i++) A[i]=(A[i-1]*1ll*(Val-i+1))%mod;
        for(int i=1;i<=m;i++) ifac=(ifac*1ll*i)%mod;
        ifac=qpow(ifac,mod-2);
        for(int i=2;i<=m;i++){
            int sum=A[i-1],u=(Val+mod-(i-2))%mod;
            f[i]=(sum+mod-f[i-1]-((((u*1ll*f[i-2])%mod)*1ll*(i-1))%mod))%mod;
        }
        printf("%lld
    ",(f[m]*1ll*ifac)%mod);
        return 0;
    }
    
    
  • 相关阅读:
    如何获取下拉框中的值
    如何建立主从服务器
    hibernate
    Python基础(一)
    python2 与 python3 区别
    canvas简述(二)游戏实战思路
    canvas简述(一)
    C简述(二)
    C语言的基本简述
    Js基础(三) WebAPI
  • 原文地址:https://www.cnblogs.com/NLDQY/p/11910884.html
Copyright © 2011-2022 走看看