• CF1314G解题报告


    题意

    给定数组(p)和两个串(s)(t)(|s|ge|t|),我们称(s')(t)是相等的当且仅当(forall iin[0,len(t)),t_i=s'_i or t_i=p_{s'_i}),问对于(s)每一个位置开始的长度为(len(t))的子串是否与(t)相等。

    (|s|,|t|le2*10^5)

    题解

    对于双字符串匹配(KMP)不能用的情况下,一般是(FFT)

    对于此题,如果(sum_{j=0}^{m-1}(t_j-s_{i+j})^2(t_j-p_{s_{i+j}})^2=0)则说明(t)(s)(i)位置上匹配了。

    展开得到(t_j^4+(-2p_{s_{i+j}}-2s_{i+j})t_j^3+(p_{s_{i+j}}^2+4s_{i+j}p_{s_{i+j}}+s_{i+j}^2)t_j^2\+(-2s_{i+j}p_{s_{i+j}}^2-2s_{i+j}^2p_{s_{i+j}})t_j+s_{i+j}^2p_{s_{i+j}}^2),观察到这个式子实际上是关于(s)(t)的卷积,考虑将(s)(t)翻转(考虑最后输出答案,我们选择翻转(t)),那么这个求和就是一个卷积的形式,可以快速用(FFT)求出。

    Code

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define Mp make_pair
    #define pb push_back
    using namespace std;
    
    using ll = long long;
    using db = double;
    using pii = pair<int, int>;
    using vi = vector<int>;
    
    -----ntt板子-----
    
    const int P = 998244353, N = 2e5 + 100;
    int n, m, val[30], p[30], s_[5][N], t_[5][N], ans[N]; char s[N], t[N];
    signed main(){
    	// freopen("data.in", "r", stdin);
    	// freopen("my.out", "w", stdout);
        srand(time(0));
    	for(int i = 0; i < 26; i++) val[i] = (ll)rand * rand() % P; // 随机权值,降低出错概率
    	for(int i = 0, q; i < 26; i++) scanf("%d", &q), p[q - 1] = i;
    	scanf("%s%s", t, s); n = strlen(s), m = strlen(t);
    	for(int i = 0; i < n; i++) {
    		s[i] -= 'a';
    		ll u = val[s[i]], v = val[p[s[i]]];
    		s_[4][i] = 1;
    		s_[3][i] = (-2 * v - 2 * u) % P;
    		s_[2][i] = (v * v + 4 * u * v + u * u) % P;
    		s_[1][i] = (-2 * u * v * v - 2 * u * u * v) % P;
    		s_[0][i] = u * u%P * v%P * v % P;
    	}
    
    	// printf("s_:
    ");
    	// for(int i = 0; i < 5; i++) {
    	// 	printf("	%d:", i);
    	// 	for(int j = 0; j < n; j++) printf("%d ", s_[i][j]);
    	// 	puts("");
    	// }
    	// puts("----------------------");
    
    	for(int i = 0; i < n; i++) for(int j = 0; j < 5; j++) if(s_[j][i] < 0) s_[j][i] += P;
    	for(int i = 0; i < m; i++) {
    		ll u = val[t[i] - 'a']; t_[0][i] = 1;
    		for(int j = 1; j < 5; j++) t_[j][i] = t_[j - 1][i] * u % P;
    	}
    	// printf("s_:
    ");
    	// for(int i = 0; i < 5; i++) {
    	// 	printf("	%d:", i);
    	// 	for(int j = 0; j < n; j++) printf("%d ", s_[i][j]);
    	// 	puts("");
    	// }
    	// printf("t_:
    ");
    	// for(int i = 0; i < 5; i++) {
    	// 	printf("	%d:", i);
    	// 	for(int j = 0; j < m; j++) printf("%d ", t_[i][j]);
    	// 	puts("");
    	// }
    	for(int x = 0; x < 5; x++) {
    		reverse(t_[x], t_[x] + m); // 翻转得到卷积,翻转t_防止结果逆序
    		vi res = multiply(vi(s_[x], s_[x] + n), vi(t_[x], t_[x] + n));
    		for(int i = m - 1; i < n; i++) ans[i] += res[i], ans[i] %= P;
    	}
    	for(int i = m - 1; i < n; i++) putchar(ans[i] ? '0' : '1'); putchar('
    ');
    	fprintf(stderr, "time=%.4f
    ", (db)clock()/CLOCKS_PER_SEC);
    	return 0;
    	/* 取模直接除,爆零两行泪
    	 * 不开ll见祖宗
    	 */
    }
    
  • 相关阅读:
    hdu 1175
    hdu 2197
    STL的学习
    数据结构之线性结构栈
    Linux下Fork与Exec使用
    散列技术之哈希
    检索之二分检索
    检索之顺序检索
    程序员该怎样放松?8个好网站推荐
    外部碎片和内部碎片的区别
  • 原文地址:https://www.cnblogs.com/JHDHJjuruo/p/12680562.html
Copyright © 2020-2023  润新知