题目链接:
题目大意:
给 n n 个数 , m m 个数 ;问在 A A 中选 个或 2 2 个数,能构成 (指相加) 多少个 中的数?
数据范围:
1≤n,m≤2e51≤Ai,Bi≤2e5 1 ≤ n , m ≤ 2 e 5 1 ≤ A i , B i ≤ 2 e 5
解题思路:
DP的复杂度不够,只想到一个比较好的暴力,送上一发TLE;后经 cp 大佬强力优化,终于在T,W之后看到了AC!
赛后发现大佬用 bitset 做的,嗯,,,bitset,了解一下?
定义:
主要有三种构造方式:
bitset <16> A;
bitset <16> B (0xfa2); //十六进制构造
bitset <16> C (string("011001")); //字符串构造
//A: 0000000000000000
//B: 0000111110100010
//C: 0000000000011001
基本运算:
什么与(&),或(|),非(~),异或(^),左移(<<),右移(>>) 都是有的!等于(==),不等于(!=)也都是有的。
C++ bitset 内部实现是非常 nice 的!很快!
基本函数:
bt.count()
//1 的个数
bt.any()
//返回是否有1
bt.none()
//返回是否没有1
bt.set()
//全部置为1
bt.reset()
//全部置为0
bt.set(p)
//把 p 位置为1
bt.reset(p)
//把 p 位置为 0
bt.set(p, x)
//把 p 位置为 x (x为0 或 1)
bt.flip()
//全部取反
bt.flip(p)
//把 p 位取反
bt.to_string()
//转为 string
回到题目上来;只要把选
1
1
个数 和 选 个数能构成的状态处理出来,跟
B
B
数组的状态与 (&) 一下,统计 的个数就可以了。
AC代码:
/**********************************************
*Author* :XzzF
*Created Time* : 2018/5/24 16:14:29
*Ended Time* : 2018/5/24 16:23:52
*********************************************/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <string>
#include <bitset>
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const LL INF = 1LL << 60;
const int MaxN = 200000;
int n, m;
int a[MaxN + 5];
bitset <MaxN + 1> A, B, ans;
int main()
{
while(scanf("%d", &n) != EOF)
{
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
A.set(a[i]);
}
scanf("%d", &m);
for(int i = 1; i <= m; i++) {
int x;
scanf("%d", &x);
B.set(x);
}
ans |= (B & A); //只选1个数
for(int i = 1; i <= n; i++) //选2个数
ans |= (B & (A << a[i]));
printf("%d\n", ans.count());
A.reset(); B.reset(); ans.reset();
}
return 0;
}
强行打一波广告:压位卡常题必备神器,bitset,值得拥有!