原题链接:蓝桥杯算法训练VIP-统计单词个数
解题思路:
为什么要用哈希呢?它可以判断字符串是否出现(主要是害怕TLE).
这里用的字符串哈希是把str当作一个base进制数处理,因为字母有26个(废话),所以这里选用29这个稍大一些的质数作为基数,顺便取个膜100003(而不是100007或100009什么的)
至于dp就很简单了(写给像我一样看不懂题解的蒟蒻们),设f[i][k]为前i个字符分成了k断的最优解,显然状态可以这样转移:f[i][k]=max{f[j][k-1]+s[j+1][i],k-1<=j<i}.s[l][r]表示从l->r有多少个单词(可以暴力预处理),若过一段分成了k小段,那么这一段至少有k个字符(废话),这就是j要大于等于k-1的原因.
好了,看代码:
注意事项:
参考代码:
#include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<iostream> using namespace std; int len=0; char zfc[300]; int p,k; char wl; void dr()//读入 { while(p--)//p没有用了…… { for(int i=0;i<20;i++)//每行20个 { scanf(" %c",&wl);//注意有空格——" %c" zfc[len++]=wl;//将新的字符加入到大字符串中 } } }char dt[10][300]={0};//存每个可以使用的匹配单词,即字典int gs;//字典单词个数 int kmp[10][300]={0};//kmp匹配函数int ln[10]; //存字典中每个单词的长度 bool visit[300];//防止重复统计,即题意中的“不能重复开头” int xx[10];//每个单词目前匹配的位数,具体在KMP函数中int sum; //统计一段单词中可以匹配的总个数 int ct(int zuo,int you)//KMP函数(匹配函数){ sum=0; memset(visit,false,sizeof(visit)); memset(xx,0,sizeof(xx)); for(int i=zuo;i<=you;i++) { for(int j=0;j<gs;j++) { while(xx[j]&&zfc[i]!=dt[j][xx[j]])xx[j]=kmp[j][xx[j]]; if(zfc[i]==dt[j][xx[j]])xx[j]++;//KMP过程 if(xx[j]==ln[j]&&!visit[i-ln[j]+1])//已经匹配到全部,且开头未被统计过 { visit[i-ln[j]+1]=true; sum++;//计数 } } } return sum;//返回计数 } int main() { scanf("%d%d",&p,&k); dr(); scanf("%d",&gs); for(int i=0;i<gs;i++)scanf("%s",dt[i]);//读入 int x; for(int i=0;i<gs;i++)//KMP匹配序列生成 { kmp[i][0]=kmp[i][1]=0; ln[i]=strlen(dt[i]); x=0; for(int j=1;j<ln[i];j++) { while(x&&dt[i][x]!=dt[i][j])x=kmp[i][x]; kmp[i][j+1]=dt[i][x]==dt[i][j]?++x:0; } } int f[300][300]={0}; for(int i=0;i<len;i++) { for(int j=1;j<=k;j++) { if(j==1) { f[i][j]=ct(0,i);//一段直接匹配 } else { for(int k=0;k<i;k++) { if(f[k][j-1]) f[i][j]=max(f[i][j],f[k][j-1]+ct(k+1,i));//取最大值 } } } } printf("%d",f[len-1][k]);//输出 return 0; }
0.0分
5 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复