zoukankan      html  css  js  c++  java
  • HDU 3336 Count the string

    HDU 3336 Count the string:

    题目:https://vjudge.net/problem/HDU-3336

    分析:题目让我们求所有前缀在字符串中出现的次数,我们就假设dp[i] 为0 ~ i 这个前缀对答案的贡献,假如所有前缀在字符串中只出现一次,那么dp[i] = 1,但是现实情况肯定不是所有前缀只出现一次的,如果我们遍历到0~i 这个前缀,发现他有公共前后缀,这就说明前面的一个前缀被重复了,那么这个答案就dp[i] = 1(这个子缀本身)+1(与前缀重复的后缀) = 2吗?不一定,你怎么知道这个这个相同的前后缀没有公共前后缀?例如 a a c d a a 我们遍历到最后一个a,我们发现整个串aacdaa有最长公共前后缀为aa,说明前面的前缀aa在aacdaa中被重复了一次, 但同时最前面的a在这aacdaa中也被重复了一次,所以子串aacdaa对答案的贡献是1(它本身)+1(aa)+1(a) = 3,为什么没有倒数第二个a,他不是也被重复了吗,因为倒数第二个a在枚举到字串aacda的过程中已经被算过了。这样分析下来就有种递推的感觉,就是不断去跳next,跳一次答案加1

    分析起来感觉不太简单,但写起来就只有一个式子,如果你看过其他题解也会发现:

    [dp[i] = dp[nexts[i]]+1 ]

    其实给你只需要给你dp数组的含义这个式子就非常容易写出来,这里我称dp[i] 为0~i 这个子串的出现对答案的贡献,如果某个字串没有最长公共前后缀,那么dp[i] = 1,如果有,那他对答案的贡献就不只是他自己了,还多个后缀对答案的贡献,这个后缀在哪个位置呢?nexts[i] ,贡献为多少呢? dp[nexts[i]] ,所以这个式子就出来了

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <vector>
    using namespace std;
    const int MOD = 10007;
    const int maxn = 200000+50;
    int dp[maxn];
    vector<int> nexts;
    int T,N; 
    string str;
    void build(string a){
    	int n = a.size();
    	nexts.resize(n+1);
    	nexts[0] = -1;
    	for(int i = 0,j = -1; i < n; nexts[++i] = ++j){
    		while(~j && a[i] != a[j]) j = nexts[j];
    	} 
    }
    void solve()
    {
    	cin>>N;
    	cin>>str;
    	for(int i = 0; i <= str.size(); i++) dp[i] = 0;
    	int ans = 0;
    	build(str);
    	for(int i = 1; i <= str.size(); i++){
    		dp[i] = (dp[nexts[i]] + 1) % MOD;
    		ans = (ans + dp[i]) % MOD;
    	}
    	cout<<ans<<endl; 
    }
    int main()
    {
    	ios::sync_with_stdio(0);
    	cin.tie(0);cout.tie(0);
    	cin>>T;
    	for(int i = 1; i <= T; i++) solve();
    	return 0;
    }
    
    "没有天赋异禀,那就加倍努力"
  • 相关阅读:
    老男孩九期全栈Python之基础一
    为善如挽逆水之舟,才放手便下流
    对自己的表现打分
    anki
    解决推送数据平台
    己所独知,尽是方便;人所不见,尽是自由
    常与权
    为什么会一直刷视频而停不下来
    准备换个房子
    UDEC 1
  • 原文地址:https://www.cnblogs.com/Beic233/p/13047971.html
Copyright © 2011-2022 走看看