E-Sort String 字符串hash+hash表做法
这题一开始就想到了要O(1)得到起始点为i(0~len-1)长度为len的每一个串的hash值,但是在这之后如果不能O(n)的在容器里将他们分类排序的话基本上就超时(sort排序超了凉凉);
用字符串hash将翻倍了的字符串hash一遍,然后O1得到每一个len长的串的hash值,将每一个很大的hash值用hash表存起来分配到vector里输出;
这题用了双hash,hash值里用到的INF如果是1e9的话还是有可能hash冲突的(就比如说我这个非洲人就wa了,别人交就过了。)
///耗时:817ms(菜鸡的代码,写的很挫) 内存使用:152288kb
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6+1e5+7, w=26;
const ll INF=2e9;///这个值为1e9可能还会有冲突
void write(int x){
if(x==0){putchar(48);return;}
int len=0,dg[20];
while(x>0){dg[++len]=x%10;x/=10;}
for(int i=len;i>=1;i--)putchar(dg[i]+48);
}
int len, cnt;
struct has
{
ll P;
ll mi_w[maxn];
ll hs[maxn];
void init(char *s)
{
P=1e9+rand();
mi_w[0]=1;
for(int i=1; i<=len; i++)
mi_w[i]=mi_w[i-1]*w%P;
for(int i=1; i<=len; i++)
hs[i]=(hs[i-1]*w+s[i]-'0')%P;
}
ll get(int l,int r)
{
return ((hs[r]-hs[l-1]*mi_w[r-l+1])%P+P)%P;
}
bool ok(int l,int r)
{
return (get(1,l)+get(l+1,r)-get(r+1,len))%P==0;
}
}h[2];
const int Size=2333237;///hash表用的mod
struct Hash{
int num[Size];
ll key[Size];
void init(){
memset(num, 0, sizeof(num));
memset(key, -1, sizeof(key));
}
int Insert(ll x){
int num1=x%Size;
while(key[num1]!=-1){
if(key[num1]==x){
return num[num1];
}
++num1;
if(num1>=Size)
num1-=Size;
}
key[num1]=x;
num[num1]=cnt++;
return num[num1];
}
}th;
char str[maxn];
vector<int> vv[maxn/2];
int main(){
register int j, i, slen, top, sav;
register ll aaa;
srand(time(0));
scanf("%s", str+1);
len=slen=strlen(str+1);
th.init();
len*=2;
for(i=1;i<=slen;++i)///翻倍
str[i+slen]=str[i];
h[0].init(str);
h[1].init(str);
cnt=0;
for(i=1; i<=slen; ++i){
aaa=h[0].get(i, i+slen)*INF+h[1].get(i, i+slen);
sav=th.Insert(aaa);///插入的时候如果插入过这个数字就返回保存的下标值,没插入过就返回新保存的下标值
vv[sav].push_back(i-1);
}
write(cnt);
putchar('\n');
for(i=0; i<cnt; ++i){
sav=vv[i].size();
write(sav);
for(j=0; j<sav; ++j)
putchar(' '), write(vv[i][j]);
putchar('\n');
}
}
用next数组找循环节的方法刚刚补了一下,果然快了好多;
耗时:138ms 内存使用:14056kb
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+7;
int Next[N];
void write(int x){
if(x==0){putchar(48);return;}
int len=0,dg[20];
while(x>0){dg[++len]=x%10;x/=10;}
for(int i=len;i>=1;i--)putchar(dg[i]+48);
}
void getNext(char *s, int &len){
Next[0]=-1;
register int i=0,k=-1;
while(i<len){
if(k==-1||s[i]==s[k]){
Next[++i]=++k;
}
else{
k=Next[k];
}
}
}
char str[N];
int main(){
register int i, j, len, cnt;
scanf("%s", &str);
len=strlen(str);
getNext(str, len);
if(len%(len-Next[len])==0&&Next[len]){
cnt=len-Next[len];
write(len-Next[len]);
putchar('\n');
for(i=0; i<cnt; ++i){
write(len/(len-Next[len]));
for(j=i; j<len; j+=cnt){
putchar(' ');
write(j);
}
putchar('\n');
}
}else{
write(len);
putchar('\n');
for(i=0; i<len; ++i){
putchar('1');
putchar(' ');
write(i);
putchar('\n');
}
}
}

