编程之美_集合

时间限制: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
  • 分析:

    思考一下问题的本质,对于两个不相交的集合A和B,假设f值不相等那么答案为1。假设相等那么答案为2。对于全部的A和B的情况(设为P),设A和B相等的情况(设为x),那么结果就等于(P + x)/ 2。计算两个数的值相等能够用异或为零,那么就能够用dp来攻克了dp【n】【异或值】

  • 重点:

    这个题目答案是须要对m取模的,而答案的计算中包含了一个除法,所以须要额外处理。在计算中,对于p和x肯定是取过模的,否则计算不出来。

    可是这个题有点特殊。最后结果是除以2,也就是右移一位,也就是说假设我们一直对2*m取模的话,最后右移一位(除以2)结果就对了。

    延伸一下。对于仅仅含有对2^n做除法的式子且终于结果对m取模,我们能够通过对m * 2^n取模,最后直接除以2^n就可以

  • 总结:

    对于推断两个数相等。能够採用异或值为零来解决。

代码是赛后自己写的,没有依照题目要求,懂什么意思即可,(小数据,未取模)

忽略之吧..... 才发现这个对于n=20的数据规模是不行的

const int MAXN = 1100;
const double PI = acos(-1.0);

int dp[MAXN];

int main()
{
//    freopen("in.txt", "r", stdin);
    int n;
    while (cin >> n)
    {
        CLR(dp, 0);
        int all = (1 << n) - 1;
        for (int i = 1, cnt = 1; cnt <= n; cnt++, i <<= 1)
        {
            FED(j, all, 0)
            {
                if (j & i)
                {
                    dp[j] = dp[i ^ j] ^ cnt;
                }
            }
        }
        int ans = 0;
        FE(i, 0, all) FE(j, 0, all)
        {
            if (!(i & j) && dp[i] >= dp[j]) ans++;
        }
        WI(ans);
    }
    return 0;
}

大数据的:(没有处理取模)

const int MAXN = 1100;
const double PI = acos(-1.0);

LL dp[2][MAXN];

LL my(int n)
{
    LL ret = 1;
    for (int i = 0; i < n; i++) ret *= 3;
    return ret;
}

int main()
{
//    freopen("in.txt", "r", stdin);
    int n;
    while (cin >> n)
    {
        int cur = 0, all;
        CLR(dp, 0); dp[cur][0] = 1;
        for (all = 1; all <= n; all <<= 1);
        all -= 1;
        for (int cnt = 1; cnt <= n; cnt++)
        {
            cur ^= 1;
            CLR(dp[cur], 0);
            FE(j, 0, all)
            {
                dp[cur][j] += dp[cur ^ 1][j];
                dp[cur][j ^ cnt] += dp[cur ^ 1][j] * 2;
            }
        }
        cout << (my(n) + dp[cur][0]) / 2 << endl;
    }
    return 0;
}
时间: 2024-11-05 18:52:14

编程之美_集合的相关文章

编程之美初赛第二场 集合

题目3 : 集合 时间限制: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组输入数据,测试数据之间没有空行. 每组数

【C#的学习旅程】Linq _2015编程之美挑战赛初赛 CodeHunt赛区

序言 2015 编程之美挑战赛·初赛结束了,小伙伴们似乎都在Hihocoder上愉快的玩耍-- 只有我一个人默默地打着Code Hunt-- 啊对了,默默的全题3SP的AK了哟-- 来逐题写下题解和解题源码吧-- (P.S 有什么不好的或者说得不对的地方请告诉我哦,我会立马改正的~(●'?'●)) Section 00 BAIYUN 00.01 Tutorial 教程 点进去会有一个小动画,亲切的告诉你玩法, 新手们可以看看这个哦~~ 00.02 求最值 Math里有这样一个函数,返回a与b之间

编程之美--3.3

题目描述:计算相似度,其实本质就是计算编辑距离 思路:一开始先递归,然后加备忘改DP,发现有很多重复子问题,再重新设计dp算法 1 #include <iostream> 2 #include <queue> 3 #include <climits> 4 #include <algorithm> 5 #include <memory.h> 6 #include <stdio.h> 7 using namespace std; 8 9

编程之美之数独求解器的C++实现方法

编程之美的第一章的第15节,讲的是构造数独,一开始拿到这个问题的确没有思路, 不过看了书中的介绍之后, 发现原来这个的求解思路和N皇后问题是一致的, 但是不知道为啥,反正一开始确实没有想到这个回溯法,知道是用回溯法求解之后,问题就变得容易了很多. 这里我们不打算实现数独的构造,相反的,我们实现一个数独求解器,以后妈妈再也不用担心我的数独了. 当然求解器的思路和构造数独的思路一样,都是回溯法搜索,这里不再过多说明. 程序运行说明: 1.把待求解的数独数据放到in.txt文件中, 程序会自动读取他,

java并发编程之美-阅读记录1

1.1什么是线程? 在理解线程之前先要明白什么是进程,因为线程是进程中的一个实体.(线程是不会独立存在的) 进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程中的一个执行路径,一个进程中至少会有一个线程,进程中的多个线程共享进程的资源. 线程:是cpu分配的基本单位. 由上图可看出,一个进程中会有多个线程,多个线程共享堆和方法区,但是每一个线程都会有自己的栈和程序计数器. 为什么要将栈和程序计数器设置为线程私有的呢? 前边说线程是cpu执行的基本单位,而cp

编程之美-分层遍历二叉树

问题:给定一个二叉树,要求按分层遍历该二叉树,即从上到下按层次访问该二叉树(每一层将单独输出一行),每一层要求访问的顺序为从左到右,并将节点依次编号.那么分层遍历如图的二叉树,正确的输出应该为: <span style="font-size:14px;">1 2 3 4 5 6 7 8</span> 书中还给出了问题2:打印二叉树中的某层次的节点(从左到右),其中根结点为第0层,成功返回true,失败返回false 分析与解法 关于二叉树的问题,由于其本身固有的

读书问题之《编程之美》 -----12061161 赵梓皓

我阅读的书是<编程之美> 刚开始的时候阅读序,就觉得控制cpu利用率这个问题很好玩,所以重点看了这部分和解决办法,问题也都大部分是这部分的.那么问题就来了(挖掘机技术xxx?中国山东找蓝翔) 咳咳,问题在下面: 1.关于问题的提出.(也是一点点建议) 本书的主要内容是告诉读者如何思考问题和解决问题.但是提出问题也是很重要的,正如爱因斯坦所说“提出一个问题往往比解决一个问题更重要”,很多面试题(比如井盖为啥是圆的)我觉得正常人很少会想到.所以,这个问题是怎么想出来的...我很好奇.也希望作者能够

《编程之美》3.6判断链表是否相交之扩展:链表找环方法证明

先看看原题:<编程之美>3.6编程判断两个链表是否相交,原题假设两个链表不带环. 为了防止剧透使得没看过原题目的读者丧失思考的乐趣,我把最好的解法隐藏起来.由于这个问题本身的解答并不是本文的重点,扩展问题也采用这种形式呈现. 注:位于(*)符号之间的文字出自于:http://blog.csdn.net/v_july_v/article/details/6447013,作者v_JULY_v. 用指针p1.p2分别指向两个链表头,不断后移:最后到达各自表尾时,若p1==p2,那么两个链表必相交 用

黑马程序员_集合

集合1.集合和对象数组的区别: 数组的长度不可变,集合的可变: 数组可以存储基本数据类型和对象,集合只能存储对象. 集合的框架图 集合派系的顶层接口Collection1.Collection集合存储对象的方法: add(E e)将元素存储到集合中 addAll(Collection c)将一个集合添加到另外的集合中2.Collection集合提取对象的方法: 通过迭代器iterator中的方法:hasNext()和next()来取出 Iterator it=new iterator(); wh