爱思创 180912 AK串 II 题解
题目思路
题目大意
给定整数 \(n\) 和 \(m\),\(n\) 表示AK串的位数,\(m\) 表示所有 \(n\) 位AK串中不允许出现的前缀,求出合法的 \(n\) 位AK串的个数。(AK串指只由字符A和K组成的固定位数的字符串)
我们用枚举法来做这一道题,用状态压缩来常数优化
我们把题目分成两部分,输入部分和处理部分
输入部分
先定义两个数组,一个存前缀(不存字符串,存整数,二进制代表字符串),另一个存前缀的长度。
每次输入一个字符串,就要把字符串转化成整数
建一个函数int trans(string)
里面我们把 'A' 设为1,'K'设为0
每次乘2在加1或0
然后把得到的数的二进制的后面补0直到 \(n\) 位
int trans(string k)
{
int x = 0;
for(int i = 0; i < k.size(); i ++)
{
if(k[i] == 'A')
{
x <<= 1;//左移1位比乘2更快
x += 1;
}
else x <<= 1;
}
x <<= (n - k.size());//左移补0
return x;
}
处理部分
先写一个框架
for(int i = 0; i < (1 << n); i ++)//枚举一切长度为n的AK串
{
if(check(i))//重点:判断前缀
{
ans ++;
}
}
然后写check()函数
把每一个前缀枚举一遍,用&来取前缀,再与非法前缀比较
bool check(int k)
{
for(int i = 1; i <= m; i ++)
{
int t = (1 << len[i]) - 1;//最后len[i]位为1
t <<= (n - len[i]);//t左移
int y = t & k;//前缀
if((y ^ ffc[i]) == 0) return false;//相同
}
return true;
}
完整代码
#include<bits/stdc++.h>
using namespace std;
int ffc[20], len[20], n, m;
int trans(string k)
{
int x = 0;
for(int i = 0; i < k.size(); i ++)
{
if(k[i] == 'A')
{
x <<= 1;
x += 1;
}
else x <<= 1;
}
x <<= (n - k.size());
return x;
}
bool check(int k)
{
for(int i = 1; i <= m; i ++)
{
int t = (1 << len[i]) - 1;
t <<= (n - len[i]);
int y = t & k;
if((y ^ ffc[i]) == 0) return false;
}
return true;
}
int main()
{
int ans = 0;
cin >> n >> m;
string s;
for(int i = 1; i <= m; i ++)
{
cin >> s;
ffc[i] = trans(s);
len[i] = s.size();
}
for(int i = 0; i < (1 << n); i ++)
{
if(check(i))
{
ans ++;
}
}
cout << ans;
return 0;
}
hello, I'm yuzihang, if you need to copy this, please quote this url: https://www.cnblogs.com/yuzihang/articles/16927218.html

浙公网安备 33010602011771号