题意很简单,给一个长度不大于200000的字符串,求长度在A-B之间的子串出现的频率,输出前N大频率的子串。
这题卡了我很久,一直在纠结使用哪种算法,然后为写这题硬是学会了KMP,发现用不上,又去学AC自动机,发现一些细节不好处理,然后终于找到一种简单的算法,哈希。
要申明的是这个代码是借鉴别人的写的,而且借鉴了很多。非原创。
/*
ID: modengd1
LANG: C++
TASK: contact
*/
#include <iostream>
#include <cstring>
#include <vector>
#include <map>
#include <stdio.h>
#include <algorithm>
using namespace std;
int a,b,n;
map<string,int> mm;
vector<pair<int,string> > vv;
bool cmp(pair<int,string> a,const pair<int,string> b)
{
if(a.first!=b.first)return a.first>b.first;
else if(a.second.size()!=b.second.size())
return a.second.size()<b.second.size();
else return a.second<b.second;
}
int main ()
{
freopen("contact.in","r",stdin);
freopen("contact.out","w",stdout);
scanf("%d %d %d%\n",&a,&b,&n);
string str;
char ch;
while(~scanf("%c",&ch))
{
if(ch=='\n')
continue;
str.push_back(ch);
}
for(int len=a;len<=b;len++)
for(int j=0;len+j<=str.size();j++)
mm[str.substr(j,len)]++;
for(map<string,int>::iterator it=mm.begin();it!=mm.end();++it)
{
pair<int,string> p(it->second,it->first);
vv.push_back(p);
}
sort(vv.begin(),vv.end(),cmp);
int pt=0;
int last=-1;
int counter=0;
int re=0;
while(pt<vv.size())
{
if(vv[pt].first!=last)
{
if(re==n)break;
if(re!=0)cout<<endl;
re++;
counter=0;
cout<<vv[pt].first<<endl<<vv[pt].second.c_str();
last=vv[pt++].first;
}
else
{
counter++;
if(counter%6==0)
{
cout<<endl<<vv[pt].second.c_str();
}
else
cout<<" "<<vv[pt].second.c_str();
pt++;
}
}
cout<<endl;
return 0;
}