bzoj4503: 两个串 bitset

题目链接

bzoj4503: 两个串

题解

暴一发bitset
f[i][j] 表示 S[1..i] 是否有个后缀能匹配 T[1..j]
那么假设 S[i+1] 能匹配 T[s],令 f[i+1][s] | = f[i][s-1]
所以预处理理出每个字符能匹配 T的哪些位置,设为[c]
那么 f[i]=((f[i-1]<<1)|(1<<1)) & mat[S[i]]
直接在mat上做匹配就好了
时间复杂度:O(|S||T|/32)

代码

#include<cstdio>
#include<bitset>
#include<cstring>
#include<algorithm>
#define LL long long
#define gc getchar()
#define pc putchar
#define LD long double
inline int read() {
    int x = 0,f = 1;
    char c = gc;
    while(c < '0' || c > '9' )c = gc;
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc;
    return x * f ;
}
void print(int x) {
    if(x >= 10) print(x / 10);
    pc(x % 10 + '0');
}
const int maxn = 100007;
char s[maxn],t[maxn];
std::bitset<maxn>mat[30],ans;
int main() {
    scanf("%s%s",s + 1,t + 1);
    int n = strlen(s + 1),m = strlen(t + 1);
    for(int i = 1;i <= n;++ i) mat[s[i] - 'a'].set(i);
    ans.set();
    for(int i = 1;i <= m;++ i)
        if(t[i] != '?') ans &= (mat[t[i] - 'a'] >> (i - 1));
    int cnt = 0;
    for(int i = 1;i <= n - m + 1;++ i) if(ans[i] == 1) cnt ++;
    print(cnt);
    pc('\n');
    for(int i = 1;i <= n - m + 1;++ i) if(ans[i] == 1)print(i - 1),pc('\n');
    return 0;
}  

原文地址:https://www.cnblogs.com/sssy/p/9769359.html

时间: 2024-10-09 00:41:55

bzoj4503: 两个串 bitset的相关文章

BZOJ4503 两个串 FFT

题目传送门 - BZOJ4503 题意概括 给定两个字符串S和T,回答T在S中出现了几次,在哪些位置出现.注意T中可能有?字符,可以匹配任何字符. 题解 首先,假装你已经知道了这是一道$FFT$题. 考虑怎样$FFT$. 字符串匹配的时候,对于匹配成功的对应字母的编号(比如分别是$i$和$j$),满足了$i-j$都相同.但是我们需要的是$i+j$都相等. 于是我们用$FFT$的经典套路,翻转$T$串. 我们构造一个卷积: $\sum_{i=0}^{n}\sum_{j=0}^{m}(S_{i}-T

bzoj4503 两个串

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4503 [题解] 我们设匹配函数f = (a[i]-b[i])^2*b[i] 那么展开f,做卷积就能得出f的值了 对于t[i]=='?',b[i]=0,显然当f=0表示匹配,那么直接FFT即可. 我记得有道类似的题,两串都有通配符匹配,就把f改成(a[i]-b[i])^2a[i]b[i]就ok了. # include <math.h> # include <stdio.h> #

bzoj4403 两个串

Description 兔子们在玩两个串的游戏.给定两个字符串S和T,兔子们想知道T在S中出现了几次, 分别在哪些位置出现.注意T中可能有“?”字符,这个字符可以匹配任何字符. Input 两行两个字符串,分别代表S和T Output 第一行一个正整数k,表示T在S中出现了几次 接下来k行正整数,分别代表T每次在S中出现的开始位置.按照从小到大的顺序输出,S下标从0开始. 两个串a,b相等(b中有通配符)当且仅当Σ(a[i]-b[i])2b[i]=0,其中a[i],b[i]为对应字符的对应编号,

UESTC 883 方老师与两个串

CF原题 由题可知,n,m太大,无法开出dp[n][m]的数组. 观察发现s/e最大为300,也就是说,选用第一种操作的次数不会超过300. 于是定义dp[i][j],第一个串的前i个数,使用了j次第一种操作的时候,第二个串最少删了多少个数. 转移有两种情况: 1.当前位置不删,这时dp[i][j]=dp[i-1][j]: 2.当前位置删,此时就需要在B串中找和当前位置的数相同的数的位置,并且只有在找到的位置大于dp[i-1][j-1]的时候才是可行的.为了保证dp[i][j]最小,显然就是找大

数据结构——算法之(032)(求两个串中的第一个最长子串)

[申明:本文仅限于自我归纳总结和相互交流,有纰漏还望各位指出. 联系邮箱:[email protected]] 题目: 求两个串中的第一个最长子串(神州数码曾经试题).如"abractyeyt","dgdsaeactyey"的最大子串为"actyey". 题目分析: 1.这里仅仅是实现了简单的字符串算法(最大支持字符串长度64),主要是展示算法思想 2.思路是把2个字符串每一个字符的匹配关系,映射到一张二维数组表中,匹配写1,非匹配写0 算法实现

求两个串的最大子序列(非字串)

问题:求两个串的最大子序列(并非连接的) Java代码: import java.util.Set; import java.util.StringJoiner; public class Main { public static int getL(String a, String b) { if (a.isEmpty()||b.isEmpty()) return 0; if (a.charAt(0) == b.charAt(0)) return getL(a.substring(1), b.s

SPOJ 1811 Longest Common Substring(求两个串的最长公共子串)

http://www.spoj.com/problems/LCS/ 题目:求两个串的最长公共子串 分析: 以A建立SAM 让B在SAM上匹配可以类比于kmp思想,我们知道在Parent树上,fa是当前节点的子集,也就是说满足最大前缀,利用这个就可以做题了 #include <bits/stdc++.h> #define LL long long #define P pair<int, int> #define lowbit(x) (x & -x) #define mem(a

BZOJ 4503 两个串(FFT)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4503 [题目大意] 给出S串和T串,计算T在S中出现次数,T中有通配符'?'. [题解] 我们定义f[x]=sum_{i=0}^{n-1}|s1[i]-s2[i]|,当f[x]=0时,两个字符串相等.因为考虑到这里还有适配符,所以用f[x]=sum_{i=0}^{n-1}(s1[i]-s2[i])*(s1[i]-s2[i])*s1[i]*s2[i]来表示匹配函数.我们可以发现,如果将

BZOJ 4503 两个串 ——FFT

[题目分析] 定义两个字符之间的距离为 (ai-bi)^2*ai*bi 如果能够匹配,从i到i+m的位置的和一定为0 但这和暴力没有什么区别. 发现把b字符串反过来就可以卷积用FFT了. 听说KMP+暴力可以卡到100ms以内(雾) [代码] #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using na