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;
    }
    
    
  • 相关阅读:
    Binary Tree Inorder Traversal
    Populating Next Right Pointers in Each Node
    Minimum Depth of Binary Tree
    Majority Element
    Excel Sheet Column Number
    Reverse Bits
    Happy Number
    House Robber
    Remove Linked List Elements
    Contains Duplicate
  • 原文地址:https://www.cnblogs.com/zjlcnblogs/p/11627811.html
Copyright © 2011-2022 走看看