牛客 - Prize(bitset优化暴力)

题目链接:点击查看

题目大意:给出一个长度为 n 的模式串 s ,再给出一个长度为 m 的匹配串,匹配串的每一位的可行数字都会给出,现在问最多可以匹配多少个字符串

题目分析:模式串和匹配串的匹配,AC自动机的经典问题,但是在这个题目中匹配串的个数过于多,所以并不能这样做,因为匹配串的长度比较短,所以可以预处理出一个可行数组用来记录哪个位置可以放置哪个数字,这样就能将时间复杂度优化为 n * m 暴力贪心匹配了,但是看数据范围可知,n 为 2e6 , m 为 800 ,显然出题人是有意卡掉这样的暴力匹配

考虑优化,其实我们可以使用 bitset 优化暴力,可以使得时空复杂度降低 64 个常数,优化方法非常巧妙:

首先就是利用 bitset 数组来充当可行数组,设其为 b 数组,即 bitset<800>b[ 10 ],则 b [ i ][ j ] = 1 代表第 j 个位置上允许放置数字 i,然后利用一个 bitset 变量记录每一次的匹配状态,记这个变量为 cur,cur 的含义是:模式串遍历到位置 i 时,cur 的第 j 位的状态代表着 [ i - j + 1 , i ] 这段区间是否和匹配串的前 j 个字符匹配,注意 cur 的每一位都是相互独立的

每一次对于 cur 的操作是,令其左移一位,再将第一个位置置为 1 ,设当前遍历到的数字为 num ,则接下来就令 cur &= b[ num ] ,因为 b[ num ] 中存放的二进制为 1 的位置代表着可以放置字符 num 的位置,所以在进行 “ 或 ” 运算后,cur 中仍然为 1 的位置 j 表示在第 [ i - j + 1 , j - 1 ] 这段区间与匹配串的前 j - 1 个字符匹配的基础上,第 j 个字符仍然匹配,所以根据动态规划的思想可以巧妙地将状态转移为 cur 的第 j  个位置也为 1

综上所述,每次只要 cur 的第 m 个位置为 1 时,就说明当前连续的 m 个字符匹配成功,答案加一且将 cur 清空

代码:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=2e6+100;

int a[N];

bitset<810>b[10],cur,pre;

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%1d",a+i);
	for(int i=1;i<=m;i++) 
	{
		int k;
		scanf("%d",&k);
		while(k--)
		{
			int num;
			scanf("%d",&num);
			b[num][i]=1;
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		pre<<=1;
		pre[1]=1;
		cur=pre&b[a[i]];
		if(cur[m])
		{
			ans++;
			cur.reset();
		}
		pre=cur;
	}
	if(ans==0)
		puts("Failed to win the prize");
	else
		printf("%d\n",ans);





    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Frozen_Guardian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值