HDU 3336(kmp+dp +HDU 4300
hdu 3336
题目:给出一个字符串,问该字符串的每个前缀在字符串中出现的次数之和。
思路:需要对next数组有足够的理解。设dp[i]表示以i结尾的字符串中出现的总次数(答案),那么首先在next[i]到i之间的前缀不会是对应的后缀,所以该长度的串数量恰好是dp[next[i]]+1。
UPD:今天又看了一下,感觉之前理解得很不到位....首先dp[i]的意义是以i结尾的后缀在前缀中出现的次数,然后通过next走到到前缀都是该后缀的后缀,但是长度都比该后缀要短.然后这显然不会重复,最后的答案要累加所有dp值(因为他们的位置都是不同的,但是可能是相同的串)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxlen=1e6+300; int fail[maxlen]; int T; void getFeil(char *s,int *f){ int len=strlen(s); int i=0,j=f[0]=-1; while(i<len){ while(j!=-1&&s[j]!=s[i]) j=f[j]; f[++i]=++j; } } const int mod=10007; int n; char r[maxlen]; int dp[maxlen]; int main(){ freopen("/home/files/CppFiles/in","r",stdin); //freopen("test.in","r",stdin); //freopen("test.out","w",stdout); cin>>T; while(T--){ scanf("%d %s",&n,r); getFeil(r,fail); int len=strlen(r); dp[0]=0; int ans=0; for(int i=1;i<=len;i++){ dp[i]=dp[fail[i]]; dp[i]++; dp[i]%=mod; ans+=dp[i]; ans%=mod; } cout<<ans<<endl; } return 0; }
hdu 4300
题目:给你一个加密方法,和一个序列,序列前半部分是加密信息,后半部分是原来的信息,但是后半部分可能缺损(前半部分肯定完整),问可能的最短原串.
思路:把整个串解密和原串接在一起,用kmp看看前缀和后缀的匹配长度,然后细节上讨论一下即可.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-6) #define IINF (1<<29) #define LINF (1ll<<59) #define INF (1000000000) #define FINF (1e3) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; const int maxlen=1e6+300; int fail[maxlen]; int T; void getFeil(char *s,int *f){ int len=strlen(s); int i=0,j=f[0]=-1; while(i<len){ while(j!=-1&&s[j]!=s[i]) j=f[j]; f[++i]=++j; } } const int mod=10007; int n; char r[maxlen]; char tmp[maxlen]; char d[maxlen]; char dir[maxlen]; int dp[maxlen]; int main(){ freopen("/home/files/CppFiles/in","r",stdin); //freopen("test.in","r",stdin); //freopen("test.out","w",stdout); cin>>T; while(T--){ scanf("%s",d); scanf("%s",r); for(int i=0;i<26;i++){ dir[d[i]-'a']=i+'a'; } int len=strlen(r); for(int i=0;i<len;i++){ tmp[i]=dir[r[i]-'a']; } tmp[len]=0; strcat(tmp,r); getFeil(tmp,fail); if(fail[len*2]<=len/2){ printf("%s",r); for(int i=fail[len*2];i<len-fail[len*2];i++){ printf("%c",tmp[i]); } }else{ printf("%s",r); int t=len-fail[len]; if(len%t!=0||(len%t==0&&len/t%2)) for(int i=len%t;i<t;i++){ printf("%c",r[i]); } } puts(""); } return 0; }