3374 String Problem
2016-06-05 22:36
239 查看
String Problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2521 Accepted Submission(s): 1063
Problem Description
Give you a string with length N, you can generate N strings by left shifts. For example let consider the string “SKYLONG”, we can generate seven strings:
String Rank
SKYLONG 1
KYLONGS 2
YLONGSK 3
LONGSKY 4
ONGSKYL 5
NGSKYLO 6
GSKYLON 7
and lexicographically first of them is GSKYLON, lexicographically last is YLONGSK, both of them appear only once.
Your task is easy, calculate the lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), its times, lexicographically last string’s Rank (if there are multiple answers, choose the smallest one), and its times also.
Input
Each line contains one line the string S with length N (N <= 1000000) formed by lower case letters.
Output
Output four integers separated by one space, lexicographically fisrt string’s Rank (if there are multiple answers, choose the smallest one), the string’s times in the N generated strings, lexicographically last string’s Rank (if
there are multiple answers, choose the smallest one), and its times also.
Sample Input
abcder
aaaaaa
ababab
Sample Output
1 1 6 1
1 6 1 6
1 3 2 3
题意大意:给你一个字符串,求它的同构字符串中字典序最小的和字典序最大的起始位置以及出现的次数。同构字符串指的是一个字符串通过循环移位得到的字符串,题目中也有解释,应该是可以看懂的。
思路:
(一)求出它的同构循环串,用map存储出现的次数,然后排序,就可以求出答案了。代码如下,提交超内存。
<span style="font-size:18px;">#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#define LL long long
using namespace std;
const int maxn = 1000000+5;
struct node{
string s;
int r;
}ss[maxn];
bool cmp(node x,node y)
{
if(x.s!=y.s) return x.s<y.s;
return x.r<y.r;
}
int main()
{
cin.sync_with_stdio(false);
string a,b;
int la,c;
while(cin>>a){
map<string,int>m;
la=a.size();
c=0;
m[a]++;
ss[c].s=a;
ss[c++].r=1;
for(int i=1;i<la;i++){
b=a.substr(i)+a.substr(0,i);
//cout<<"b="<<b<<endl;
ss[c].s=b;
ss[c++].r=i+1;
m[b]++;
}
sort(ss,ss+c,cmp);
//for(int i=0;i<c;i++) cout<<ss[i].s<<' '<<ss[i].r<<endl;
cout<<ss[0].r<<' '<<m[ss[0].s]<<' ';
int t=la-1;
while(ss[t].s==ss[t-1].s){
t--;
if(t==0) break;
}
cout<<ss[t].r<<' '<<m[ss[t].s]<<endl;
}
return 0;
}</span>
(二)用最小表示法求字典序最小的字符串,最大表示法求字典序最大的字符串,next数组求出现的次数。
最小表示法:已知了起始坐标就可以唯一确定同构循环串,分别用i和j表示两个不同的循环串的起始位置,k表示比较的长度,解释一下下面的语句吧
if(s[(i+k)%ls]>s[(j+k)%ls]) i=i+k+1; //因为s[i]~s[(i+k-1)%ls]==s[j]~s[(j+k-1)%ls],所有当s[(i+k)%ls]>s[(j+k)%ls]时可以得出i~(i+k-1)%ls中以任意坐标开始的都要比j~(j+k-1)%ls的要大,所有i可以直接等于i+k+1
next数组可以求出一个字符串的循环节,比如字符串s,ls=s.size(),那么s的循环节的长度len=ls-next[ls],所有出现的次数为ls/len。 这个AC
<span style="font-size:18px;">#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<map> #define LL long long using namespace std; const int maxn = 1000000+5; int Next[maxn]; void getNext(string s) { int ls=s.size(); Next[0]=-1; Next[1]=0; for(int i=2;i<=ls;i++){ if(s[i-1]==s[Next[i-1]]) Next[i]=Next[i-1]+1; else{ int t=Next[i-1]; while(s[i-1]!=s[t]){ t=Next[t]; if(t==-1) break; } Next[i]=t+1; } } } int getMin(string s) { int ls=s.size(); int i=0,j=1,k=0; while(i<ls && j<ls && k<ls){ //k<ls 一定要写,因为当s=aaaaa时不写会死循环 if(s[(i+k)%ls]==s[(j+k)%ls]) k++; else{ if(s[(i+k)%ls]>s[(j+k)%ls]) i=i+k+1; else j=j+k+1; if(i==j) j++; k=0; } } return min(i,j); } int getMax(string s) { int ls=s.size(); int i=0,j=1,k=0; while(i<ls && j<ls && k<ls){ if(s[(i+k)%ls]==s[(j+k)%ls]) k++; else{ if(s[(i+k)%ls]>s[(j+k)%ls]) j=j+k+1; else i=i+k+1; if(i==j) j++; k=0; } } return min(i,j); } int main() { cin.sync_with_stdio(false); //记得用c++要加这一句,因为不加会超时 string s; int ls,len,smin,smax; while(cin>>s){ getNext(s); ls=s.size(); len=ls-Next[ls]; smin=getMin(s)+1; smax=getMax(s)+1; cout<<smin<<' '<<ls/len<<' '<<smax<<' '<<ls/len<<endl; } return 0; }</span>
相关文章推荐
- 1、TCL脚本基本语法(概要)
- 静态库和动态库的区别
- android 界面布局 很好的一篇总结
- Linux下的第一步——进度条(gcc&Makefile)
- C++作业7
- c++作业7
- C/C++值传递,指针传递和引用传递的概念
- vim简易教程
- Exchange 2010 PS之New-SendConnector&get-SendConnector&Set-sendConnector!
- c++拾遗-----内存模型
- Android Studio教程从入门到精通
- Chapter 2. C++程序设计入门
- net core VS goang web
- vue简单使用
- openmp在图像处理上面的运用
- NOSql之redis的学习
- sql语句判断两个时间段是否有交集
- 存储过程、触发器和用户自定义函数实验 (存储过程)
- c++实验7-最大公约数和最小公倍数
- hiho 题目1 : 非法二进制数(数位dp)