您的位置:首页 > 其它

hdu2609-字符串最小表示法|模拟|二分+lcp-How many

2017-08-23 14:41 357 查看
http://acm.hdu.edu.cn/showproblem.php?pid=2609

给你m个串,长度相等。只有0和1组成,

他们都可以把后面的 放在前面。并且这种串算作相同的

比如 1100 1001 0011 0110 这四个。

问你m个中有多少不同的。

暴力写的,后来看别人的题解。最小表示法,O(n),,类似用两个指针 来比较,利用的是 字典序的相关特质,

还有一个lcp+二分的,先mark。

#include <bits/stdc++.h>
using namespace std;
/* 或者用 字符串的最小表示法。
用来解决字符串的同构问题。
同构即 一个字符串最后面的移动到前面,然后
形成总共 (长度len)个 串,这些串同构。
*/
const int maxn=2e5;
int  MINR(string s){
int len=s.length();
int i=0;int j=1;
//int k=0;
while(i<len/2&&j<len/2){
int k=0;
while(s[i+k]==s[j+k]&&k<len/2) k++;
if(k==len/2) return min(i,j);
if(s[i+k]>s[j+k])// 若求最大,把大于改成小于,下面也是。
i=max(i+k+1,j+1);
else if(s[i+k]<s[j+k])
j=max(j+k+1,i+1);
}
return min(i,j);
}
int main()
{    int t;
string s[maxn];
vector<string>w;
while(~scanf("%d",&t)){
w.clear();
for(int i=0;i<t;i++){
cin>>s[i];
s[i]+=s[i];
}
for(int i=0;i<t;i++){
int r=MINR(s[i]);
//cout<<r<<endl;
//cout<<s[i].substr(r,s[i].length()/2)<<endl;
w.push_back(s[i].substr(r,s[i].length()/2));

}
sort(w.begin(),w.end());
w.erase(unique(w.begin(),w.end()),w.end());
/*for(int i=0;i<w.size();i++){
cout<<w[i]<<endl;
}*/
printf("%d\n",w.size());
}
return 0;
}


暴力。比那个慢点

bitset应该也行,不过得自己写。。

#include <bits/stdc++.h>
using namespace std;
/* bitset模拟。
srting

*/
const int maxn=1e5;
int main()
{    int n;
string s[maxn];
set<string>se;
while(cin>>n){
se.clear();
for(int i=0;i<n;i++){
cin>>s[i];
s[i]+=s[i];
//s[i]+=s[i];
// cout<<s[i]<<endl;
}
// cout<<s[0][0]<<endl;
vector<string> kk;
for(int i=0;i<n;i++){
{   kk.clear();
for(int j=0;j<s[i].length()/2;j++){
//cout<<s[i][j]<<endl;
string w=s[i].substr(j,s[i].length()/2);
//cout<<w<<endl;
kk.push_back(w);
}
sort(kk.begin(),kk.end());
//cout<<kk[0]<<endl;
se.insert(kk[0]);
}
}
//set<string>::iterator it;
//for(it=se.begin();it!=se.end();it++)
// cout<<*it<<endl;
printf("%d\n",se.size());

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: