hdu 3336 (Count the string) next数组+dp
这一题很早很早以前就遇到了,一直一来迟迟没有动手。
直到昨天为止,做了足够多的”前戏“,才敢下手。
题目大意:给定一个字符串,比如 abab,找出i(1=<i<=n)个单位长度的前缀在字符串中出现的次数和。
前缀 出现次数
a 2
ab 2
aba 1
abab 1
所以,答案就是6;
用dp[i]记录字符串中前i个字符中所包含的前缀个数。
i dp[i] 包含的前缀 next[i]
1 1 a 0
2 1 ab 0
3 2 a,aba 1
4 2 ab,abab 2
通过上面的列表可以发现,前i个字符至少含有一个前缀,那就是它本身;
当i=3时,为何有两个前缀?有nex数组的意义可以知道:因为next[3]=1,即从1到3是一个循环周期,而在这个循环内是不会再含有更多的前缀了!
所以当求前i个字符所包含的前缀个数时,只需考虑他的上一个循环周期的dp[next[i]]再加他本身就ok了;
状态转移方程:
dp[i]=dp[next[i]]+1;
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 #define N 200005 6 int next[N]; 7 char str[N]; 8 int dp[N]; 9 int t,n; 10 void get_next() 11 { 12 13 int i=0,j=-1; 14 next[0]=-1; 15 while(i<n) 16 { 17 18 if(j==-1||str[i]==str[j]) 19 { 20 21 i++; 22 j++; 23 next[i]=j; 24 } 25 else 26 j=next[j]; 27 28 } 29 // for(i=1;i<=n;i++) 30 // printf("%d ",next[i]); 31 // printf("\n"); 32 } 33 int main() 34 { 35 // freopen("input.txt","r",stdin); 36 // freopen("output.txt","w",stdout); 37 38 scanf("%d",&t); 39 while(t--) 40 { 41 42 scanf("%d",&n); 43 getchar(); 44 scanf("%s",str); 45 memset(next,-1,sizeof(next)); 46 get_next(); 47 int i; 48 memset(dp,0,sizeof(dp)); 49 int sum=0; 50 for(i=1;i<=n;i++) 51 { 52 53 dp[i]=(dp[next[i]]+1)%10007; 54 sum=(sum+dp[i])%10007; 55 } 56 57 // for(i=1;i<=n;i++) 58 // printf("%d ",dp[i]); 59 // printf("\n"); 60 61 printf("%d\n",sum); 62 } 63 return 0; 64 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?