编程之美初赛第二场 集合

这么晚才写编程之美的解题报告,想记录下自己学习算法的过程。本题出于于2014年编程之美初赛第二场。

题目转述

时间限制:
12000ms 单点时限:
6000ms 内存限制:
256MB

描述

统计满足下列条件的集合对(A, B)的数量:

  • A,B都是{1, 2, …, N}的子集;

  • A,B没有公共的元素;

  • f(A)<= f(B)f(S)定义为S中所有元素的按位异或和。例如, f({}) = 0, f({1, 3}) = 2。

因为答案可能很大,你只需要求出它除以M的余数。

输入

第一行一个整数T (1 ≤ T ≤ 10),表示数据组数。

接下来是T组输入数据,测试数据之间没有空行。

每组数据格式如下:

仅一行,2个整数N和M (1 ≤ M ≤ 108)。

输出

对每组数据,先输出“Case x: ”,然后接一个整数,表示所求的结果。

数据范围

小数据:1 ≤ N ≤ 20

大数据:1 ≤ N < 212

样例输入

1
3 100000000

样例输出

Case 1: 18

解法

      对于集合U={1, 2, ……, N}的任意一个划分{A,B},肯定对应着一个划分{B,A},两者至少有一个满足要求。如果f(A)<f(B),则只有{A,B}满足。如果f(A)>f(B),则{B,A}满足。如果f(A)=f(B),则两个都满足。设所有子集组合{A,B}的数目为X,其中满足f(A)=f(B)的数目为Y,则满足要求的集合对数为X/2+Y/2.

      先考虑计算X,对于任意一个组合{A,B}, 集合U的所有元素均有三个去处即{A, B, 剩余其他元素},所以总数目是3^N。对于这里的组合{A,B}是有顺序的,即{A,B}和{B,A}是两种方案。当{A,B}={B,A}时,即A=B,只能是A和B均为空。所以总的数目X=(3^N-1),排除空集。

      然后计算Y的数目。对于{A,B}满足f(A)=f(B),必有f(AUB)=0。反过来,对于有k个元素的集合R={r1,r2,…,rk},如果f(R)=0,则将R划成两个集合的办法个数为《编程之美初赛第二场 集合》所以,只需要找出所有满足f(R)=0的子集。下面采用动态规划来计算满足f(AUB)=0的方案数。

      定义dp[i][j]表示前i个数分配好的情形下,两个集合异或值为j的方案数。则满足f(A)=f(B)的方案数即为dp[N][0]。有状态转移方程如下:

      dp[i+1][j] = (dp[i][j] + 2 * dp[i][j^(i+1)])

理解为,前面i+1个数,异或结果为j的方案数,可以分成两类:一是不选择i+1,即dp[i][j]。二是选择i+1,将i+1加入到异或结果为j^(i+1)的两个集合中任意一个,都会得到一个新方案,异或结果为j.

      初始状态:dp[0][0]=1,即两个均为空集的方案。dp[0][j]=0, j > 0。

      dp[N][0]的结果中,{A,B}和{B,A}会被计算成两种,但空集方案仅一种,即dp[0][0]=1。排除空集方案,Y=dp[N][0]-1。所以,总的方案数NUM=X/2+Y/2+1(空集)=(3^N+dp[N][0])/2。

      在N较大的情况下,NUM要对M求余。求余必须渗透于计算过程中的每一步,即3^N和dp[N][0]的计算过程。有一个小麻烦,就是除以2如何处理。

      先证明除以2的等价计算方法。假设现在要求x/2对M的余数,首先计算x对2M的余数,不妨设为r,令x=2Mk+r(k是整数)。于是x/2=Mk+r/2。x/2对M的余数就是r/2,且不论x的奇偶性。

      所以,该问题简化为,在计算3^N+dp[N][0]的过程中,对2M求余。最后余数除以2即得NUM对M的余数,可以记为(3^N+dp[N][0])%(2M)/2。

      本文分析到此结束,欢迎大家探讨!

    原文作者:无名大盗
    原文地址: https://blog.csdn.net/dreamer2020/article/details/27144051
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞