题意

题目链接

Sol

不愧是dls出的比赛啊,265个交了题的人只有8个有分Orz

做完这题,,感觉自己的位运算dp姿势升华了。。。

首先最裸的dp应该比较好想,设\(f[i][j][k]\)表示前\(i\)个数选出来的数异或和为\(j\),按位与和为\(k\)的方案数

转移的时候讨论一下该位置选不选,最后只要统计\(f[N][i][i]\)的答案

比较坑的是这题在写的时候不能用一般的pull写法,也就是说不能从前面的状态转移而来,因为我们不知道应该从哪儿转移而来。

仔细想想也比较显然,就拿与运算来说,它在运算过程中会丢失掉一部分信息

比如\(k = 1001, a[i] = 1011\),我们不清楚他是从\(1101\)转移而来还是\(1001\)转移而来。

时间复杂度:\(O(n * 8192 * 8192) = GG\)

int N, a[MAXN], Lim = 128, f[2][1235][1235];
main() {
N = read();
for(int i = 1; i <= N; i++) a[i] = read();
f[0][0][Lim - 1] = 1;
int o = 0;
for(int i = 1; i <= N; i++, o ^= 1) {
for(int j = 0; j < Lim; j++)
for(int k = 0; k < Lim; k++)
f[o ^ 1][j][k] = f[o][j][k]; for(int j = 0; j < Lim; j++)
for(int k = 0; k < Lim; k++)
f[o ^ 1][j ^ a[i]][k & a[i]] += f[o][j][k];
}
int ans = 0;
for(int i = 0; i <= Lim; i++) ans += f[o][i][i];
cout << ans;
return 0;
}

接下来是神仙优化部分:

先考虑简单一点的。

显然,如果选出来的数与起来的第\(i\)位为\(1\),那么显然所有数的这一位都为\(1\)。

如果我们再知道数的个数奇偶性,那么就可以知道这种情况是否合法。同理,若这一位是0,也可以按照奇偶性判断

复杂度:\(O(2 * N * 13 * 8192)\)

事实上,转移是可以优化到O(1)的。

设\(x\)为选出来的数的异或和,\(y\)为选出来的数的按位与

若选出来的数为偶数个,那么\(x \& y = 0\)

若选出来的数为奇数个,那么\(x \& y = y\)

那么每个位上的状态都可以由一个三元组\((xx, y, k)\)表示

  1. 都为1:\(xx = 0, y = 0\)

  2. 有奇数个1:\(xx = 1, y = 0\)

  3. 有偶数个1:\(xx = 0, y = 0\)

再加上奇偶性(这个不需要压在状态里面),总的状态数为\(2 \times 3^{13}\)

我们可以预处理出所有的\(S(xx, y)\)的状态,转移的时候直接加上就行了。

最终的答案 = \(f[N][S(0, 0)][0]\) + \(\sum f[N][i][1] (xor[i] = 0)\)

做题的时候我对\(y\)和\(xx\)之间的关系纠结了好久

很显然,\(xx\)的二进制表示是\(y\)的补码的子集

因为\(xx\)是不考虑所有位都为1的情况的,而其余的位置又没有限定

另外就是\(x\)与\(xx\)的相互转化

  • \(x\) to \(xx\)

如果\(k\)是奇数,那么\(x = xx | y\),否则\(x = xx\)

可以直接由最开始的结论得到

  • \(xx\) to \(x\)

xx = x & (-y)

可以直接由定义得到

比着一份极其风骚的代码抄了一遍。。。

可能还有一些神奇的逻辑关系没有注意到。。有空再看看。

#include<bits/stdc++.h>
#define file(x) freopen(x, "r", stdin);
#define LL long long
const int MAXN = 2e6 + 10, Lim = 8192, INF = 1e9 + 7;
using namespace std;
inline int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, tot, a[51], And[MAXN], Xor[MAXN], S[Lim + 1][Lim + 1];
LL f[2][MAXN][2];
void Pre() {
for(int i = 0; i < 8192; i++) {
int x = (~i) & (Lim - 1);
for(int j = x; ; j = (j - 1) & x) {
And[tot] = i; Xor[tot] = j; S[j][i] = tot++;
if(j == 0) break;
}
}
}
main() {
// file("a.in")
N = read();
for(int i = 1; i <= N; i++) a[i] = read();
Pre();
int o = 0; f[0][S[0][Lim - 1]][0] = 1;
for(int i = 1; i <= N; i++, o ^= 1) {
int nxt = o ^ 1;
for(int j = 0; j < tot; j++)
f[nxt][j][0] = f[o][j][0],
f[nxt][j][1] = f[o][j][1];
for(int j = 0; j < tot; j++) {
for(int k = 0; k < 2; k++) {
if(!f[o][j][k]) continue;
int x = Xor[j], y = And[j];
if(k) x = x | y;
x ^= a[i]; y &= a[i]; x &= (~y);
// printf("%d %d %d\n", x, y, S[x][y]);
f[nxt][S[x][y]][!k] += f[o][j][k];
}
}
}
LL ans = f[o][S[0][0]][0];
for(int i = 1; i < tot; i++) if(Xor[i] == 0) ans += f[o][i][1];
cout << ans;
return 0;
}

HihoCoder#1279 : Rikka with Sequence(dp 枚举子集 二进制 神仙题)的更多相关文章

  1. UVA 11825 - Hackers&#39; Crackdown 状态压缩 dp 枚举子集

    UVA 11825 - Hackers' Crackdown 状态压缩 dp 枚举子集 ACM 题目地址:option=com_onlinejudge&Itemid=8&page=sh ...

  2. [Luogu P3959] 宝藏 (状压DP+枚举子集)

    题面 传送门:https://www.luogu.org/problemnew/show/P3959 Solution 这道题的是一道很巧妙的状压DP题. 首先,看到数据范围,应该状压DP没错了. 根 ...

  3. UVa 11825 - Hackers' Crackdown DP, 枚举子集substa = (substa - 1)&sta 难度: 2

    题目 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&a ...

  4. 计蒜客习题:蒜头君的积木 (状压DP 枚举子集)

    问题描述 蒜头君酷爱搭积木,他用积木搭了 n 辆重量为 wi的小车和一艘最大载重量为 W 的小船,他想用这艘小船将 n 辆小车运输过河.每次小船运载的小车重量不能超过 W.另外,小船在运载小车时,每辆 ...

  5. BZOJ 2560: 串珠子 (状压DP+枚举子集补集+容斥)

    (Noip提高组及以下),有意者请联系Lydsy2012@163.com,仅限教师及家长用户. 2560: 串珠子 Time Limit: 10 Sec Memory Limit: 128 MB Su ...

  6. P5911 [POI2004]PRZ (状态压缩dp+枚举子集)

    题目背景 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 题目描述 桥已经很旧了, 所以它不能承受太重的东西.任何时候队伍在桥上的人都不能超过一定的限制. 所以这只队伍过桥时 ...

  7. UVA 11825 Hackers’ Crackdown 状压DP枚举子集势

    Hackers’ Crackdown Miracle Corporations has a number of system services running in a distributed com ...

  8. [POI2004]PRZ [枚举子集]

    怎么全是 模拟退火 啊,这明明是个 枚举子集 的板子题. 考虑 \(n \leq 16\) 二进制没错了.. \(dt_i\) 表示 \(i\) 这个状态下 \(\max{t_j}\),\([\tex ...

  9. uva 11825 Hackers&#39; Crackdown (状压dp,子集枚举)

    题目链接:uva 11825 题意: 你是一个黑客,侵入了n台计算机(每台计算机有同样的n种服务),对每台计算机,你能够选择终止一项服务,则他与其相邻的这项服务都终止.你的目标是让很多其它的服务瘫痪( ...

随机推荐

  1. 【洛谷2416】泡芙(Tarjan+LCA)

    题目描述 火星猫经过一番努力终于到达了冥王星.他发现冥王星有 \(N\) 座城市,\(M\) 条无向边.火星猫准备出发去找冥王兔,他听说有若干泡芙掉落在一些边上,他准备采集一些去送给冥王兔.但是火星猫 ...

  2. gym 102082B dp

    和51nod1055 一样: #include<iostream> #include<cstdio> #include<algorithm> #include< ...

  3. c++继承构造析构调用原则以及特殊变量处理

    一.继承中的构造析构调用原则 1.子类对象在创建时会首先调用父类的构造函数 2.父类构造函数执行结束后,执行子类构造函数 3.当父类构造函数有参数时,需要在子类的初始化列表中显示调用: 4.析构函数调 ...

  4. 网址访问量统计插件 FlagCounter

    网址或博客访问量统计插件  ---> FlagCounter. 网址:http://s01.flagcounter.com/more/ERP2/

  5. Java 实现邮件的发送

                                             Java 实现邮件的发送 开发邮箱发送功能必须看邮箱方面的资料 改一些东西  (我的是qq 邮箱哟   开通 POP3 ...

  6. Chrome浏览器如何完美实现滚动截图技巧

    一.前言 我们平时在浏览网页时,想把碰到好的网页内容或者文章截屏保存,但是网页的长度常常会超出屏幕高度,一般的截屏功能只能截取显示在屏幕上的内容,那我们该如何方便快捷截取全部内容?今天就分享一个如何利 ...

  7. php 实现无限极分类

    原始数据 $array = array( array('id' => 1, 'pid' => 0, 'n' => '河北省'), array('id' => 2, 'pid' ...

  8. C#多线程函数如何传参数和返回值

          详见网站:http://WWW.MOVIH.COM就是一个多线程爬虫系统.   C#多线程函数如何传参数和返回值 提起多线程,不得不提起 委托(delegates)这个概念. 我理解的委托 ...

  9. MySQL 简洁 数据操作 增删改查 记不住的 看这里把

    1.库操作====================== 1.创建 CREATE DATABASE DB2 charset utf8; 2.删除 DROP DATABASE db2; 3.使用(进入) ...

  10. Wannafly挑战赛14 - E 并查集维护线性基区间

    给一个1-base数组{a},有N次操作,每次操作会使一个位置无效.一个区间的权值定义为这个区间里选出一些数的异或和的最大值.求在每次操作前,所有不包含无效位置的区间的权值的最大值. 线性基删除不知道 ...