【转载】[hrbust 2029] 二十世纪八十年代(状态压缩)


传送门:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=2029

经典水题,给出一大堆东西然后问存不存在。给定的内存一共只有5M,所以不要试图存下所有字符串,这明显超内存。使用map或者字典树的话,内存恐怕也远超5M了吧。
考虑到最多只有5个字符,每个字符26种可能,所以可以把每一个字符串转化为一个整数。
26^5 = 11881376种状态。假设开一个bool数组,一个bool占一个字节,那么
11881376 / 1024 / 1024 = 11.33M
依然超内存。
状态肯定是要存的,一个状态只需要一个位就够了,一个字节的bool实在是浪费,那么接下来就是想办法将bool压缩到一个位了。
自己写也可以(文章最后放出),不过STL提供了个好东西,叫bitset,这样一个状态真的就只需要一个位了。
简单介绍一下bitset:

#include<bitset>

bitset<10> bt; // 开辟了有10个位的变量,即0000000000


bt.set(6); // 将第六位设为1,那么就变为0001000000

bt.set(1); // 将第1位设为1,那么就变为0001000010


bt.test(6); // 测试第六位是否为1,在这里返回1

bt.test(2); // 第二位是0,所以返回0

这样一来,问题就变得很简单了

#include<iostream>
#include<bitset>

using namespace std;

bitset<12000000> bs;

int main()
{
char str[6];
int n, m;
while(~scanf("%d\n", &n))
{
for(int i = 1; i <= n; i++)
{
scanf("%s", str);
int len = strlen(str);
int num = 0;
for(int i = 0; i < len; i++)
num = num * 26 + str[i] - 'a';

bs.set(num);
}
scanf("%d\n", &m);
for(int i = 1; i <= m; i++)
{
scanf("%s", str);
int len = strlen(str);
int num = 0;
for(int i = 0; i < len; i++)
num = num * 26 + str[i] - 'a';

if(bs.test(num))
printf("yes\n");
else
printf("no\n");
}
}
return 0;
}

那么不用bitset呢,当然也能做。开个数组就行了。数组的每一个位置能存32个位,
首先计算一下需要开多大的int数组:
26^5 / 32 = 371293,那么就开个38W大小的数组好了。

hash[0]存的是最开始的32个位,也就是0~31位
hash[1]存的是接下来的32个位,也就是32~63位
所以整数值映射到num数组就很简单了

x = Value / 32;

y = Value % 32;

也就是第X个数组位置的第y位。

赋值:hash[x] = hash[x] | (1 << y);

判断:if(hash[x] & (1 << y))

完整代码(实际运行时间比上面的bitset还要短,效果可真好!):

#include<iostream>
using namespace std;

int hash[380000];

int gethash(char *str)
{
int len = strlen(str);
int re = 0;
for(int i = 0; i < len; i++)
re = re * 26 + str[i] - 'a';
return re;
}

int main()
{
int n, m;
char str[6];
int num, x, y;
while(~scanf("%d\n", &n))
{
for(int i = 0; i < n; i++)
{
scanf("%s", str);
num = gethash(str);
x = num / 32;
y = num % 32;
hash[x] = hash[x] | (1 << y);
}
scanf("%d\n", &m);
for(int i = 0; i < m; i++)
{
scanf("%s", str);
num = gethash(str);
x = num / 32;
y = num % 32;
if(hash[x] & (1 << y))
printf("yes\n");
else
printf("no\n");
}
}
return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值