zoukankan      html  css  js  c++  java
  • [HNOI2011]卡农(容斥/DP)

    Problem

    题目地址

    Solution

    首先对题意进行一步转换:从 ([1,2^n-1]) 中选出不重复的 (m) 的数,使它们的异或和为 (0) 的方案数。

    手推一下即可。

    为了计算方便,我们考虑顺序,最后再把顺序处理掉(即选择的集合相同,顺序不同视作不同的方案)。

    (f[i]) 表示选择 (i) 个数异或之和为 (0) 的方案数。

    由于条件异或之和为 (0),故选择了 (i-1) 个数后,最后一个数也确定了。所以全集为 (A^{i-1}_{2^n-1})(其中包含了不合法的)。

    考虑不合法的方案:

    • 1.前 (i-1) 个数的异或和为 (0),那么最后一个数自动选 (0),由于 (0 otin [1,2^n-1]),故不合法。该情况的方案数是 (f[i-1])

    • 2.前 (i-1) 个数的异或和为 (x),那么最后一个数自动选 (x),且 (x in S)(令 (S) 为前 (i-1) 个数的集合),即出现重复的数字。实际上就是前 (i-2) 个数的异或和为 (0),枚举最后选择的重复的数字,一共有 (2^n-1-(i-2)) 种选择的方案。注意我们考虑的是有顺序的,要考虑这个重复的数字放入任意一个位置,所以要再乘一个 (i-1)。所以该情况的方案数是 (f[i-2]*(2^n-1-(i-2))*(i-1))

    综上,可以得到:

    [f[i] = A^{i-1}_{2^n-1} - (f[i-1] + f[i-2]*(2^n-1-(i-2))*(i-1)) ]

    边界 (f[1]=0,f[2]=0)

    由于我们考虑了顺序,那么处理掉顺序的影响,答案应该是 (frac{f[m]}{m!})。时间复杂度 (O(n))

    Code

    Talk is cheap.Show me the code.

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
        return x * f;
    }
    const int N = 1e6+7, mod = 1e8+7;
    int n,m,pn;
    int g[N],f[N];
    int jc(int x) {
    	int res = 1;
    	for(int i=1;i<=x;++i) {
    		res = (res * i) % mod;
    	}
    	return res;
    }
    int Pow(int x,int y) {
    	int res = 1, base = x;
    	while(y) {
    		if(y&1) res = res*base%mod; base = base*base%mod; y >>= 1;
    	}
    	return res;
    }
    int Inv(int x) {
    	return Pow(x,mod-2);
    }
    void Init() {
    	pn = Pow(2,n);
    	g[0] = 1;
    	for(int i=1;i<=m;++i) g[i] = g[i-1] * ((pn-i + mod)%mod) % mod;
    }
    signed main()
    {
    	n = read(), m = read();
    	Init();
    	for(int i=3;i<=m;++i) {
    		f[i] = (g[i-1] - (f[i-1] + f[i-2]*(((pn-1) - (i-2) + mod)%mod)%mod*(i-1)%mod)%mod + mod) % mod;
    	}
    	printf("%lld
    ",f[m]*Inv(jc(m))%mod);
    	return 0;
    }
    /*
    2999 3000
    
    94342341
    */
    

    Summary

    考虑一下问题的全集,不合法方案和合法方案。只用到补集算比较简单的容斥,主要是问题的转化这一步比较难。

    多做题!

  • 相关阅读:
    Transfer-Encoding: chunked
    使用Kubeadm搭建Kubernetes集群
    连载二:Oracle迁移文章大全
    今晚直播:WLS/WAS故障基本分析介绍
    判断用户是否登录
    row_number() over (partition by a.sql_id order by a.id desc ) r
    Django admin添加用户
    从数据仓库到百万标签库,精细化数据管理,这么做就够了
    用 C 语言开发一门编程语言 — 更好的语言
    ubuntu下 全然卸载火狐浏览器
  • 原文地址:https://www.cnblogs.com/BaseAI/p/14022984.html
Copyright © 2011-2022 走看看