[关闭]
@Asuna 2017-02-17T08:52:30.000000Z 字数 2602 阅读 731

2016寒假集训队第八次作业

题解


Probelm A:最小表示法

题意:给你个环形串,让你求出从何处断开得到的字符串的字典序最小。

题解:模版题。
思路:
(1).利用两个指针i,j。初始化时i指向s[0],j指向s[1]。
(2).k=0开始,检验s[i+k]和s[j+k]是否相等,相等则k++,一直下去,直到找到第一个不相同的字符(若k试了一个字符串的长度也没找到不同,即整个串都是相同的字符。则那个位置就是最小表示位置,算法终止并返回)。该过程中s[i+k]和s[j+k]的关系有三种:

  1).s[i+k]>s[j+k],i滑动到i+k+1处,s[i-i+k-1]不会是循环字符串的"最小表示"的前缀。
  2).s[i+k]   
  3).s[i+k]==s[j+k],则k++,if(k==len)返回结果。
  若滑动后i==j,将正在变化的那个指针在+1.直到i,j把整个字符串都检验完毕,返回两者中小于len的值。
(3).返回min( i , j )

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. char str[10010];
  6. int t,len,i,j,k;
  7. int main()
  8. {
  9. cin>>t;
  10. while (t--)
  11. {
  12. cin>>str;
  13. len=strlen(str);
  14. i=0;
  15. j=1;
  16. k=0;
  17. while (i<len && j<len && k<len)
  18. {
  19. if (str[(i+k)%len]==str[(j+k)%len]) k++;
  20. else
  21. {
  22. if (str[(i+k)%len]>str[(j+k)%len]) i=i+k+1;
  23. else j=j+k+1;
  24. if (i==j) j++;
  25. k=0;
  26. }
  27. }
  28. if (i<j) cout<<i+1<<endl;
  29. else cout<<j+1<<endl;
  30. }
  31. return 0;
  32. }

Problem B:KMP

题意:两行分别为word和text,问你text中包含多少个word子串。

题解:模版题。。。mark一下学习网址。。
http://www.cppblog.com/oosky/archive/2006/07/06/9486.html

参考代码:

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cmath>
  4. #include<cstring>
  5. using namespace std;
  6. char str[10010],c[1000010];
  7. int ans,str1[10010],t;
  8. void getnext()
  9. {
  10. int i=0,j=-1,len=strlen(str);
  11. str1[0]=-1;
  12. while (i<len)
  13. {
  14. if (j==-1 || str[i]==str[j])
  15. {
  16. i++;
  17. j++;
  18. if (str[i]==str[j]) str1[i]=str1[j];
  19. else str1[i]=j;
  20. }
  21. else j=str1[j];
  22. }
  23. }
  24. void getans()
  25. {
  26. int i=0,j=0,lc=strlen(c),ls=strlen(str);
  27. while (j<lc)
  28. {
  29. if (str[i]==c[j])
  30. {
  31. i++;
  32. j++;
  33. }
  34. else
  35. {
  36. if (str1[i]==-1)
  37. {
  38. i=0;
  39. j++;
  40. }
  41. else i=str1[i];
  42. }
  43. if (i>=ls)
  44. {
  45. ans++;
  46. i=str1[ls];
  47. }
  48. }
  49. }
  50. int main()
  51. {
  52. cin>>t;
  53. while (t--)
  54. {
  55. ans=0;
  56. cin>>str;
  57. cin>>c;
  58. getnext();
  59. getans();
  60. cout<<ans<<endl;
  61. }
  62. return 0;
  63. }

Problem D:字典树

题意:统计出以某个字符串为前缀的单词数量

题解:字典树不熟啊。。但是看题感觉map可以做就尝试了下。。运用map对单词表中所有单词中出现的前缀进行存储和记录,没出现一次,进行一次加加。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<map>
  5. using namespace std;
  6. struct node
  7. {
  8. char name[20];
  9. }a[1000010];
  10. int ans[1000010];
  11. char b[50],s;
  12. int main()
  13. {
  14. map<string,int>ans;
  15. int k=0,p=0;
  16. while(scanf("%c",&s))
  17. {
  18. if (s==10 && p==0) break;
  19. else
  20. if (s==10 && p>0)
  21. {
  22. p=0;
  23. k++;
  24. }
  25. else
  26. if (s!=10)
  27. {
  28. a[k].name[p]=s;
  29. ans[a[k].name]++;
  30. p++;
  31. }
  32. }
  33. while (cin>>b) printf("%d\n",ans[b]);
  34. return 0;
  35. }

Problem E:Manacher

题意:求最长回文子串的长度。

题解:裸模版题。。mark一下学习网址。
https://segmentfault.com/a/1190000003914228

参考代码:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<cstdio>
  5. using namespace std;
  6. char c[1000010],mark[2000010];
  7. int p[2000010],len,j,d=1,maxlen,x,mx,l;
  8. int manacher()
  9. {
  10. len=strlen(c);
  11. mark[0]='$';
  12. mark[1]='#';
  13. l=2;
  14. for (int i=0; i<len; i++)
  15. {
  16. mark[l]=c[i];
  17. l++;
  18. mark[l]='#';
  19. l++;
  20. }
  21. maxlen=-1;
  22. mx=0;
  23. //cout<<mark<<endl;
  24. for (int i=1; i<l; i++)
  25. {
  26. if (i<mx) p[i]=min(p[2*x-i],mx-i);
  27. else p[i]=1;
  28. while (mark[i-p[i]]==mark[i+p[i]]) p[i]++;
  29. if (mx<i+p[i])
  30. {
  31. x=i;
  32. mx=i+p[i];
  33. }
  34. maxlen=max(maxlen,p[i]-1);
  35. }
  36. return maxlen;
  37. }
  38. int main()
  39. {
  40. while(cin>>c)
  41. {
  42. if (strcmp(c,"END")==0) break;
  43. cout<<"Case "<<d++<<": "<<manacher()<<endl;
  44. }
  45. return 0;
  46. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注