题面见http://acm.hdu.edu.cn/showproblem.php?pid=3336
给你一个字符串,让你找它的前缀在整个字符串出现的次数。
作为一个不会思考的笨比,直接用kmp去一个个计数,果不其然,t了
找了博客来看,大概就是kmp+dp,要用到kmp中的pret数组(有的人习惯叫next数组,知道就行)
dp的方程形式很简单,但很难理解。
这是原博主的原话:
如果用dp[i]表示该字符串前i个字符中出现任意以第i个字符结尾的前缀的次数,它的递推式是 dp[i]=dp[pret[i]]+1,
即以第i个字符结尾的前缀数等于以第pret[i]个字符为结尾的前缀数加上它自己本身,这里要好好理解一下,不太好解释
这个好好理解就很灵性了,orz。
仔细看dp[i]代表的含义,以第i个字符结尾的前缀,那么dp[pret[i]]代表什么呢,以第pret[i]结尾的前缀,(pret[i]的字符和i的字符是一样的)
那么dp[i]和dp[pret[i]]唯一不同的是什么呢?再看刚开始的那句话,dp[i]代表的含义,以第i个字符结尾的前缀,答案就很明显了,虽然它们结尾的字符是一样的
但dp[i]多了一个它自己本身,于是就有了那个dp方程。
#include <bits/stdc++.h> #define inf 0x3f3f3f3f #define INF 0x7fffffffffffffff typedef long long ll; const double PI=3.1415926535897931; const long long mod=1e9+7; const int MA= 1e7+10; const int ma= 2*1e5+10; const int few=1e3+10; const int maxn=1e8+10; using namespace std; ////////////////////////////////////////////// string a; int pret[ma]; int n; int dp[ma]; void pre() { int i = 0,len = -1; pret[0]=-1; while (i < n) { if(len == -1||a[i]==a[len]) { i++; len++; pret[i] = len; } else { len = pret[len]; } } return ; } int main() { int t; cin>>t; while(t--) { cin>>n; cin>>a; pre(); ll ans=0; dp[0]=0; for(int i=1; i<=n; i++) { dp[i]=dp[pret[i]]+1; cout<<"dp["<<i<<"]="<<dp[i]<<endl; dp[i]%=10007; ans=(ans+dp[i])%10007; } cout<<ans<<endl; } return 0; }
原文地址:https://www.cnblogs.com/Aracne/p/12601805.html
时间: 2024-10-09 18:55:58