首页 > 其他分享 >AtCoder Beginner Contest 307 Ex Marquee

AtCoder Beginner Contest 307 Ex Marquee

时间:2023-06-26 20:34:52浏览次数:42  
标签:AtCoder typedef const Beginner Marquee int comp db maxn

洛谷传送门

AtCoder 传送门

一开始看错题了,看了好久才发现就是个板子。。。

这个东西本质上是循环移位,我们考虑在 \(S\) 前后各添加 \(W - 1\) 个 .,例如 \(W = 5, S = \texttt{ABC}\) 时,添加后 \(S = \texttt{....ABC....}\)。此时我们发现 \(S\) 的每个长度为 \(W\) 的子串一一对应一个显示在公告板上的串。那么这就是一个带通配符字符串匹配问题。

接下来直接套 P4173 残缺的字符串即可。展开讲的话,设 \(n = |s|, m = |t|\),并且 \(t\) 要匹配 \(s\)。那我们把通配符的值设成 \(0\) 后,设 \(f_i = \sum\limits_{j = 1}^m t_j (s_{i - m + j} - t_j)^2\),那么 \(s_{i - m + 1 \sim i}\) 能匹配 \(t\) 当且仅当 \(f_i = 0\)。把平方拆开,就是若干个减法卷积。考虑翻转 \(t\),做加法卷积即可。

时间复杂度是 \(O(n \log n)\),带一个巨大常数。

这题用 NTT 会有些难受,因为 \(f_i\) 能达到 \(5 \times 10^9\),为了保证正确性必须要写双模数(我写的双模数还 T 了),FFT 比 NTT 快很多(可能是我 NTT 的实现劣了),所以我使用的是 FFT。

code
// Problem: Ex - Marquee
// Contest: AtCoder - Tokio Marine & Nichido Fire Insurance Programming Contest 2023(AtCoder Beginner Contest 307)
// URL: https://atcoder.jp/contests/abc307/tasks/abc307_h
// Memory Limit: 1024 MB
// Time Limit: 5000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 2100100;
const db pi = acos(-1);

int n, m, mp[128], a[maxn], b[maxn], r[maxn];
db f[maxn], g[maxn];
char s[maxn], t[maxn];

struct comp {
	db x, y;
	comp(db a = 0, db b = 0) : x(a), y(b) {}
};

typedef vector<comp> poly;

inline comp operator + (const comp &a, const comp &b) {
	return comp(a.x + b.x, a.y + b.y);
}

inline comp operator - (const comp &a, const comp &b) {
	return comp(a.x - b.x, a.y - b.y);
}

inline comp operator * (const comp &a, const db &b) {
	return comp(a.x * b, a.y * b);
}

inline comp operator / (const comp &a, const db &b) {
	return comp(a.x / b, a.y / b);
}

inline comp operator * (const comp &a, const comp &b) {
	return comp(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
}

typedef vector<comp> poly;

inline poly FFT(poly a, int op) {
	int n = (int)a.size();
	for (int i = 0; i < n; ++i) {
		if (i < r[i]) {
			swap(a[i], a[r[i]]);
		}
	}
	for (int k = 1; k < n; k <<= 1) {
		comp wn(cos(pi / k), sin(pi / k) * op);
		for (int i = 0; i < n; i += (k << 1)) {
			comp w(1, 0);
			for (int j = 0; j < k; ++j, w = w * wn) {
				comp x = a[i + j], y = w * a[i + j + k];
				a[i + j] = x + y;
				a[i + j + k] = x - y;
			}
		}
	}
	if (op == -1) {
		for (int i = 0; i < n; ++i) {
			a[i] = a[i] / n;
		}
	}
	return a;
}

inline poly operator * (poly a, poly b) {
	a = FFT(a, 1);
	b = FFT(b, 1);
	int n = (int)a.size();
	for (int i = 0; i < n; ++i) {
		a[i] = a[i] * b[i];
	}
	a = FFT(a, -1);
	return a;
}

void solve() {
	scanf("%d%d%s%s", &n, &m, s + 1, t + 1);
	if (m == 1) {
		puts(t[1] == '_' || s[1] == t[1] ? "1" : "0");
		return;
	}
	mp['_'] = 0;
	mp['.'] = 1;
	int ntot = 1;
	for (char c = 'a'; c <= 'z'; ++c) {
		mp[c] = ++ntot;
	}
	for (char c = 'A'; c <= 'Z'; ++c) {
		mp[c] = ++ntot;
	}
	int _n = n;
	n = -1;
	for (int i = 1; i < m; ++i) {
		a[++n] = 1;
	}
	for (int i = 1; i <= _n; ++i) {
		a[++n] = mp[s[i]];
	}
	for (int i = 1; i < m; ++i) {
		a[++n] = 1;
	}
	--m;
	for (int i = 0; i <= m; ++i) {
		b[i] = mp[t[i + 1]];
	}
	int k = 0;
	while ((1 << k) <= n + m) {
		++k;
	}
	for (int i = 1; i < (1 << k); ++i) {
		r[i] = (r[i >> 1] >> 1) | ((i & 1) << (k - 1));
	}
	reverse(b, b + m + 1);
	poly A(1 << k), B(1 << k);
	for (int i = 0; i <= n; ++i) {
		A[i] = comp(a[i] * a[i], 0);
	}
	for (int i = 0; i <= m; ++i) {
		B[i] = comp(b[i], 0);
	}
	poly C = A * B;
	for (int i = m; i <= n; ++i) {
		f[i] += C[i].x;
	}
	A = poly(1 << k);
	B = poly(1 << k);
	for (int i = 0; i <= n; ++i) {
		A[i] = comp(-2 * a[i], 0);
	}
	for (int i = 0; i <= m; ++i) {
		B[i] = comp(b[i] * b[i], 0);
	}
	C = A * B;
	for (int i = m; i <= n; ++i) {
		f[i] += C[i].x;
	}
	ll s = 0;
	for (int i = 0; i <= m; ++i) {
		s += b[i] * b[i] * b[i];
	}
	for (int i = m; i <= n; ++i) {
		f[i] += s;
	}
	int ans = 0;
	for (int i = m; i <= n; ++i) {
		ans += (fabs(f[i]) < 0.4);
	}
	printf("%d\n", ans);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:AtCoder,typedef,const,Beginner,Marquee,int,comp,db,maxn
From: https://www.cnblogs.com/zltzlt-blog/p/17506636.html

相关文章

  • AtCoder Beginner Contest(abc) 307
    A-WeeklyRecords题目大意小莫每天跑步,输入n周每天的步数,输出每周跑的总步数;解题思路签到题不多嗦了;神秘代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,m,k,idx;signedmain(){ cin>>n; intsum=0; for(inti......
  • AtCoder Beginner Contest 307 G Approximate Equalization
    洛谷传送门AtCoder传送门考虑我们如果确定了最终态\(B=(B_1,B_2,...,B_n)\),如何计算最少操作次数。显然从左往右依次使\(A_i=B_i\)。当操作到第\(i\)个位置时,此时\(A'_i=\sum\limits_{j=1}^iA_j-B_j\),所需操作次数为\(|A'_i|\)。令\(C_i=\sum\limits_{......
  • AtCoder Beginner Contest 245 Ex Product Modulo 2
    洛谷传送门AtCoder传送门很好的题。下文令\(k\)为原题面中的\(n\),\(n\)为原题面中的\(k\),\(m\)为原题面中的\(m\)。从一些简单的情况入手。1.\(m\)为质数\(k=0\)的情况是平凡的,只需要要求\(\existsi\in[1,n],a_i=0\)即可。总方案数减去不合法方案数,......
  • AtCoder Beginner Contest 307 ABCDE
    AtCoderBeginnerContest307A-WeeklyRecordsProblemStatement题意:告诉你有几个礼拜,问你每个礼拜走的路程和。Solution思路:按题意模拟,每7天加起来就行。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;intmain(){ intn; cin>>n; llsum=......
  • AtCoder Beginner Contest 267 ABCDE
    AtCoderBeginnerContest267A-SaturdayProblemStatement题意:问你给定的天到礼拜六还要几天。思路:直接算。#include<bits/stdc++.h>usingnamespacestd;intmain(){ strings; cin>>s; if(s=="Monday")cout<<6-1<<endl; elseif(s=="Tues......
  • AtCoder Beginner Contest 252 Ex K-th beautiful Necklace
    洛谷传送门AtCoder传送门不知道为什么可以想到设\(n_c\)为颜色\(c\)的出现次数,那么\(\prodn_c\)也即选的方案数\(\approx1.25\times10^{11}\)。发现\(B=\sqrt{\prodn_c}\)不大,考虑meet-in-the-middle,把所有颜色分成两部分,每一部分的\(\prodn_c\)都接近\(......
  • AtCoder Beginner Contest 212(E,F)
    AtCoderBeginnerContest212(E,F)E(dp)E题目大意为有\(n\)个点,我们需要找到\(k+1\)个点,用数组\(A\)表示,其中,\(A_i\)和\(A_{i+1}\)也不能一模一样,而且,规定\(A_0\)是\(1\),并且\(A_k\)也是\(1\),而且,还要满足下面的\(m\)种条边是不可以代表为\(A_i\)和\(A_{i+1}\),问我们可以......
  • AtCoder Beginner Contest(abc) 299
    A-TreasureChest题目大意给定一个由'|''*'和'.'组成的字符串,并且保证一定有1个'*'和2个'|',检查'*'是否在两个'|'之间;解题思路签到题不多嗦了;但是这里可以注意一下string的find函数;find(charc,intpos)意为从第pos个字符开始找字符c,返回值......
  • AtCoder Regular Contest 154 C Roller
    洛谷传送门AtCoder传送门被这题干爆了考虑把环压缩成块。这样一次操作就是,选择两个相邻的块,把左边块长度减\(1\),右边块长度加\(1\)。特判\(a,b\)所有块长都是\(1\)的情况,这种情况不能操作。排除掉上面的情况,我们断言:有解的充要条件是,存在某一种\(a\)的顺序,使得\(b......
  • 【题解】AtCoder-ABC306G Return to 1
    这也太强了!容易想到的是用若干环拼出这个\(10^{10^{100}}\),也就是这些环的\(\gcd\mid10\)。之后就不会了。先正图反图两次DFS,只留下\(1\)所在强连通分量里的边,对正图跑DFS生成树,定义其深度从\(0\)开始,然后有一个结论是:对于任何正整数\(a\),图中存在一个包含\(1\)......