题目链接  Educational Codeforces Round 40  Problem I

题意  定义两个长度相等的字符串之间的距离为:

    把两个字符串中所有同一种字符变成另外一种,使得两个字符串相等所需要操作的次数的最小值。

    求$s$中每一个长度为$t$的长度的连续子串与$t$的距离。字符集为小写字母$a$到$f$

首先解决求两个长度相等的字符串之间的距离这个问题。

$s$和$t$相同位上的字母连一条无向边,最后的答案是$s$和$t$中所有出现过的字符的个数减去这个无向图的连通块个数。

现在考虑$s$的所有子串和$t$匹配的问题。

令$s$的长度为$n$,$t$的长度为$m$

那么s的符合题意的子串一共有$n - m + 1$个。

把这$n - m + 1$个子串看成$n - m + 1$个独立的无向图,每个无向图是独立的;

现在我们两两枚举边(一共$30$条边),我们要做的就是快速求出这$n - m + 1$个无向图中,

有哪些是有这条边的。

这个时候我们把s和t转成一个$01$序列,设为$a$和$b$

在$a$和$b$中,若$a_{i} = b_{j} = 1$, 那么$c_{i-j} = 1$。

我们可以把$b$数组反转之后用FFT加速求出$c$。

那么在那些值为$1$的下标对应的无向图中就一定有这条边,并查集处理一下就好了。

时间复杂度$O(30nlogn)$

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define fi first
#define se second const double PI = acos(-1.0);
const int N = 125010; struct dsu{
int father[10];
void init(){
rep(i, 0, 7) father[i] = i;
} int getfather(int x){
return father[x] == x ? x : father[x] = getfather(father[x]);
} } c[N]; char s[N], t[N];
int a[N << 1], b[N << 1];
int n, m;
int ans[N]; struct Complex{
double x, y;
Complex(double x = 0.0, double y = 0.0) : x(x), y(y){}
Complex operator + (const Complex &b) const{
return Complex(x + b.x, y + b.y);
}
Complex operator - (const Complex &b) const{
return Complex(x - b.x, y - b.y);
}
Complex operator * (const Complex &b) const{
return Complex(x * b.x - y * b.y, x * b.y + y * b.x);
}
}; Complex x1[N << 2], x2[N << 2]; void change(Complex y[], int len){
for (int i = 1, j = len / 2; i < len - 1; i++){
if (i < j) swap(y[i], y[j]);
int k = len / 2;
while (j >= k){
j -= k;
k /= 2;
}
if (j < k) j += k;
}
} void fft(Complex y[], int len, int on){
change(y, len);
for (int h = 2; h <= len; h <<= 1){
Complex wn(cos(-on * 2 * PI / h), sin(-on * 2 * PI / h));
for (int j = 0; j < len; j += h){
Complex w(1, 0);
for (int k = j; k < j + h / 2; k++){
Complex u = y[k];
Complex t = w * y[k + h / 2];
y[k] = u + t;
y[k + h / 2] = u - t;
w = w * wn;
}
}
} if (on == -1){
rep(i, 0, len - 1) y[i].x /= len;
}
} void mul(int p[], int dp, int q[], int dq){
int len = 1;
while (len <= dp + dq) len <<= 1; rep(i, 0, dp)
x1[i] = Complex(p[i], 0); rep(i, dp + 1, len - 1)
x1[i] = Complex(0, 0); rep(i, 0, dq)
x2[i] = Complex(q[i], 0); rep(i, dq + 1, len - 1)
x2[i] = Complex(0, 0); fft(x1, len, 1);
fft(x2, len, 1); rep(i, 0, len - 1)
x1[i] = x1[i] * x2[i]; fft(x1, len, -1); rep(i, 0, dp + dq)
p[i] = (int)(x1[i].x + 0.5); rep(i, 0, dp + dq)
if (p[i] > 0) p[i] = 1; dp += dq;
} void work(int pos, int x, int y){
int fx = c[pos].getfather(x), fy = c[pos].getfather(y);
if (fx == fy) return;
assert(pos >= 1 && pos <= n - m + 1);
++ans[pos];
c[pos].father[fx] = fy;
} int main(){ scanf("%s%s", s, t); n = strlen(s), m = strlen(t);
rep(i, 1, n - m + 1) c[i].init(); rep(i, 0, 5){
rep(j, 0, 5){
if (i == j) continue;
memset(a, 0, sizeof a);
memset(b, 0, sizeof b); rep(k, 0, n - 1) a[k] = (s[k] - 'a' == i);
rep(k, 0, m - 1) b[k] = (t[k] - 'a' == j); reverse(b, b + m);
mul(a, n, b, m);
for (int k = m - 1, cnt = 1; cnt <= n - m + 1; ++k, ++cnt){
if (a[k]){
work(cnt, i + 1, j + 1);
}
}
}
} rep(i, 1, n - m + 1) printf("%d\n", ans[i]);
return 0; }

  

Codeforces 954I Yet Another String Matching Problem(并查集 + FFT)的更多相关文章

  1. CF954I Yet Another String Matching Problem 并查集、FFT

    传送门 题意:给出两个由小写$a$到$f$组成的字符串$S$和$T$($|S| \geq |T|$),给出变换$c1\,c2$表示将两个字符串中所有$c1$字符变为$c2$,求$S$的每一个长度为$T ...

  2. Codeforces.954I.Yet Another String Matching Problem(FFT)

    题目链接 \(Description\) 对于两个串\(a,b\),每次你可以选择一种字符,将它在两个串中全部变为另一种字符. 定义\(dis(a,b)\)为使得\(a,b\)相等所需的最小修改次数. ...

  3. 954I Yet Another String Matching Problem

    传送门 分析 我们先考虑暴力如何计算 对于S的子串SS,如果它有位置i使得SS[i] != T[i]那么我们就将两个字符之间用并查集连边 最后答案很明显就是并查集中所有边的个数 于是我们可以发现对于S ...

  4. 【CF954I】Yet Another String Matching Problem(FFT)

    [CF954I]Yet Another String Matching Problem(FFT) 题面 给定两个字符串\(S,T\) 求\(S\)所有长度为\(|T|\)的子串与\(T\)的距离 两个 ...

  5. Codeforces Round #582 (Div. 3)-G. Path Queries-并查集

    Codeforces Round #582 (Div. 3)-G. Path Queries-并查集 [Problem Description] 给你一棵树,求有多少条简单路径\((u,v)\),满足 ...

  6. CodeForces 828C String Reconstruction(并查集思想)

    题意:给你n个串,给你每个串在总串中开始的每个位置,问你最小字典序总串. 思路:显然这道题有很多重复填涂的地方,那么这里的时间花费就会特别高. 我们维护一个并查集fa,用fa[i]记录从第i位置开始第 ...

  7. Codeforces Round #541 (Div. 2) D(并查集+拓扑排序) F (并查集)

    D. Gourmet choice 链接:http://codeforces.com/contest/1131/problem/D 思路: =  的情况我们用并查集把他们扔到一个集合,然后根据 > ...

  8. Codeforces 755C:PolandBall and Forest(并查集)

    http://codeforces.com/problemset/problem/755/C 题意:该图是类似于树,给出n个点,接下来p[i]表示在树上离 i 距离最远的 id 是p[i],如果距离相 ...

  9. Codeforces Beta Round #5 E. Bindian Signalizing 并查集

    E. Bindian Signalizing Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset ...

随机推荐

  1. .NET非常棒的开源项目,给你意想不到的东西!

    http://www.cnblogs.com/Leo_wl/p/4560146.html

  2. 【Dual Support Vector Machine】林轩田机器学习技法

    这节课内容介绍了SVM的核心. 首先,既然SVM都可以转化为二次规划问题了,为啥还有有Dual啥的呢?原因如下: 如果x进行non-linear transform后,二次规划算法需要面对的是d`+1 ...

  3. 生成器 yield, next ,send

    重要的yield :相当于一个断层,我们再用next取拿出每一层重要的next :生成器查看装置,查看每一个断层重要的send :和next一样查看每一个段层,不过在查看第二个断层的时候,就可以对前面 ...

  4. 编译TypeScript(TypeScript转JavaScript)

    1.配置tsconfig.json文件 tsconfig.json文件配置说明 { "compilerOptions": { //生成相关说明,TypeScript编译器如何编译. ...

  5. 聊聊、Mybatis XML

    引入相应的依赖包 <dependency><groupId>org.mybatis</groupId><artifactId>mybatis-sprin ...

  6. springboot07 mysql02

    多表关系 一.表关系介绍 1. 表之间为什么要有关系 一般来讲,通常都是一张表某一类型数据,比如学生数据存储在学生表,教师数据存储在教师表,学科数据存储在学科表.但是有时候我们需要表示一个学生属于哪一 ...

  7. html页面分块加载

    方法:jQuery ajax - load() 方法 这个方法可以请求html页面,并把结果放在指定元素内.

  8. 想玩API,这些套路我来告诉你!

    小伙伴是不是时常听说各种api接口的问题呢,可能许多人第一感觉:那是什么个玩意儿,那么多人回去研究它,今天思梦PHP小编就来为你揭开他的神秘的面纱,先看一下百度百科上面的官方的解释: 其实说白了就是为 ...

  9. 【bzoj4562】[Haoi2016]食物链 拓扑排序+dp

    原文地址:http://www.cnblogs.com/GXZlegend/p/6832118.html 题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题 现在给你n个物种和m条能量流动 ...

  10. 如何实现自己的Android MVP框架?

    相信熟悉android开发的童鞋对MVP框架应该都不陌生吧,网上很多关于android中实现MVP的文章,大家可以直接搜索学习.这些文章中,MVP的实现思路基本都是把Activity.Fragment ...