51nod 1301 集合异或和——异或dp

题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1301

好题!看了TJ才会。

因为是不可重集合,所以当然有前 i 个表示A和B都考虑的前 i 个,新加一个讨论放A、放B、不放。

A<B在异或上看就是有一位,它前面的A和B都一样,该位A是0、B是1。该位可以枚举。然后就能dp了。

注意边界细节……和标程对拍真愉快……

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2005,M=4100,mod=1e9+7;
int n,m,mi,mj,lm,dp[2][M][2],ans,bin[25];
int calc(int a)
{
    int ret=0; while(a) a>>=1,ret++; return ret;
}
void ad(int &x,int y)
{
    x=(x+y>=mod?x+y-mod:x+y);
}
int main()
{
    scanf("%d%d",&n,&m);
    mi=max(n,m);  lm=calc(m);  int tmp=calc(mi);
    bin[1]=1;  for(int i=2;i<=tmp;i++) bin[i]=(bin[i-1]<<1);//tmp not lm!!!
    bin[tmp+1]=(bin[tmp]<<1);
    mj=bin[tmp+1]-1;
    for(int t=1;t<=lm;t++)
    {
        memset(dp[0],0,sizeof dp[0]);///not dp[0] if mj isn‘t gu ding
        dp[0][0][0]=1;
//        mj=1;
        for(int i=1,u,v;i<=mi;i++)
        {
            u=(i&1);v=!u;
//            if(i>=bin[mj])mj++;
//            for(int j=0;j<=bin[mj];j++)
            for(int j=0;j<=mj;j++)
            {
                dp[u][j][0]=dp[v][j][0];
                dp[u][j][1]=dp[v][j][1];
                if(i<=n)//A
                {
                    ad(dp[u][j][0],dp[v][j^i][0]);
                    ad(dp[u][j][1],dp[v][j^i][1]);
                }
                if(i<=m)//B
                {
                    bool d=(i&bin[t]);
                    ad(dp[u][j][0],dp[v][j^i][0^d]);
                    ad(dp[u][j][1],dp[v][j^i][1^d]);
                }
            }
        }
        int d=(mi&1);// mi not n!!!
        for(int i=bin[t];i<bin[t+1];i++) ad(ans,dp[d][i][1]);
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Narh/p/9607097.html

时间: 2024-10-20 17:19:56

51nod 1301 集合异或和——异或dp的相关文章

[51Nod 1301] 集合异或和 (dp)

传送门 Solution 一道比较好的dp题 想了半天组合数QAQ 首先要知道的是 A<B一定是B有一位是1且A的这位是0且前面都相等 那么肯定是要枚举这一位在哪里然后求出方案数 方案数考虑类似背包的方法分三种情况转移具体见代码 Code #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #defi

BZOJ 2734 集合选数(状态压缩DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2734 题意:给出一个由1到n的数字组成的集合.定义合法子集为若x在子集中则2x.3x均不能在子集中.求有多少个合法的子集. 思路: 1   3    9 2   6    12 4   12   36 对于上面的矩阵,我们发现就等价于不选相邻数字的方案数.因此枚举每个还没有用到的数字,建立以该数字为左上角的矩阵.接着就是状态压缩DP. int a[N][N]; i64 f[2][1<<

bzoj 4017 子序列和的异或以及异或的和

位运算很好的一个性质是可以单独每一位考虑..... 题解请看:http://blog.csdn.net/skywalkert/article/details/45401245 对于异或的和,先枚举位,求所有异或和和中该位为1的有多少个,再乘以该位的大小(2的多少次方). 即单独每一位考虑,每位带的权不一样. 对于和的异或,只需知道每一位中和的改位为1的奇偶性,就可以知道最终的异或值上该位是0还是1. 也是单独考虑每一位,看该位为0或1的条件. 1 /***********************

异或序列 [set优化DP]

也许更好的阅读体验 \(\mathcal{Description}\) 有一个长度为 \(n\)的自然数序列 \(a\),要求将这个序列分成至少 \(m\) 个连续子段 每个子段的价值为该子段的所有数的按位异或 要使所有子段的价值按位与的结果最大,输出这个最大值 \(T\)组询问 \(T\leq 10,n,m\leq 1000,a_i\leq 2^{30}\) \(\mathcal{Solution}\) 实际上数据范围可开大很多 我们贪心的一位一位的确定最终答案,即看当前考虑的位能否为\(1\

51nod 1352 集合计数(扩展欧几里得)

题目链接:传送门 题意:略 分析: 非常easy能够得到一个方程 A*x + B*y = N + 1 这式子能够用扩展GCD求出gcd,x和y,然后我们求出大于0的最小x,A*x第一个满足条件的集合firstSet,剩下的N-firstSet个集合能够直接除LCM(A,B)(A和B的最小公倍数)统计出数量. 代码例如以下: #include <stdio.h> #include <string.h> #include <iostream> #define LL long

51nod 1352 集合计数

给出N个固定集合{1,N},{2,N-1},{3,N-2},...,{N-1,2},{N,1}.求出有多少个集合满足:第一个元素是A的倍数且第二个元素是B的倍数. 提示: 对于第二组测试数据,集合分别是:{1,10},{2,9},{3,8},{4,7},{5,6},{6,5},{7,4},{8,3},{9,2},{10,1}.满足条件的是第2个和第8个. Input 第1行:1个整数T(1<=T<=50000),表示有多少组测试数据. 第2 - T+1行:每行三个整数N,A,B(1<=N

51nod 1412 AVL树的种类(经典dp)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1412 题意: 思路: 经典dp!!!可惜我想不到!! $dp[i][k]$表示i个结点,最大深度为k的形态数. 它的转移方程就是: dp[i][k] += dp[i - 1 - j][k - 1] * dp[j][k - 1] dp[i][k] += 2 * dp[i - 1 - j][k - 2] * dp[j][k - 1] j是右子树结点个数,如果除去根结点,是不

51nod 1050 循环数组最大子段和 (dp)

http://www.51nod.com/onlineJudge/questionCode.html#problemId=1050&noticeId=13385 参考:http://blog.csdn.net/acdreamers/article/details/38760805 #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; int n; ll a[100001

51nod 1378 夹克老爷的愤怒(树形DP+贪心)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378 大致题意: 一棵1e5节点的树,安放某些位置,一个位置可以控制距他的距离不超过K的所有节点, 输入树和K,求控制全图(所有节点)需要安放最少的个数 思路: 假如是线性结构,一定是从边界开始每距离2k安放一个,然后最后正好或者再放置一个,这个贪心思路所有人都会. 当是树形结构时,仍然用那个贪心,显然安放的位置越靠近根节点控制的其他节点数越多,所以这里必须从