zoukankan      html  css  js  c++  java
  • 【JZOJ6379】【NOIP2019模拟2019.10.06】小w与密码(password)

    题目大意

    给出两个串(S,T),你可以通过拼接(S)的某个前缀和(T)的某个前缀得到一个新串((S)的前缀在前),求能得到多少种不同的新串。

    Solution

    若一个串出现了多次,设它可以被表示成(s+t)(s'+t')。我们令(t')(t)更长,显然(t)(t')的一个border。尽管(t')有多个border,但实际上只用减去最长的border带来的影响,因为更短的border已经在这个长border计算过了。考虑把(t)(t')的后面去掉,剩下的(t')的一个前缀,若它在(S)中作为一个子串且不作为前缀出现,它就会被重复计算,减掉该前缀在(S)中出现次数即可。求前缀出现次数只需要将(T)(S)匹配并用(next)数组做一次后缀和。

    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N = 100007;
    
    long long ans;
    int lens, lent, next[N], num[N];
    char s[N], t[N];
    
    int main() {
    	freopen("password.in", "r", stdin);
    	freopen("password.out", "w", stdout);
    	scanf("%s%s", s + 1, t + 1);
    	lens = strlen(s + 1);
    	lent = strlen(t + 1);
    	ans = 1ll * lens * lent;
    	for (int i = 2, j = 0; i <= lent; ++i) {
    		while (j && t[j + 1] != t[i]) j = next[j];
    		if (t[j + 1] == t[i]) ++j;
    		next[i] = j;
    	}
    	for (int i = 2, j = 0; i <= lens; ++i) {
    		while (j && t[j + 1] != s[i]) j = next[j];
    		if (t[j + 1] == s[i]) ++j;
    		++num[j];
    	}
    	for (int i = lent; i >= 2; --i) num[next[i]] += num[i];
    	for (int i = 2; i <= lent; ++i) if (next[i]) ans -= num[i - next[i]];
    	printf("%lld
    ", ans);
    	return 0;
    }
    
    
  • 相关阅读:
    Java异常之初认识二
    Java异常之初认识
    enum类型用于switch语句
    数组指定元素查找 之 二分法查找
    数组元素查找 之 线性查找
    数组的反转
    枚举类 Enum 之初认识
    求数组元素的最大值,最小值,总和,平均数
    clone()方法引发的对protected权限修饰符的思考
    完成一个朋友圈的表设计
  • 原文地址:https://www.cnblogs.com/zjlcnblogs/p/11627811.html
Copyright © 2011-2022 走看看