牛客网多校3 Sort String(后缀数组DC3)

本文介绍了一道关于字符串操作的算法竞赛题目,通过DC3算法、KMP算法及哈希方法解决如何生成不同字符串的问题,并详细展示了每种方法的具体实现过程。

题目:就是给你一个串,对于第i个位置,你可以把前i个字符放到队尾形成一个新的字符串,问你最后一共有几个字符串

DC3卡过去了hhhh

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
using namespace std;
const int maxn=2000001;
int wa[maxn*3],wb[maxn*3],wv[maxn*3],wss[maxn*3];
int c0(int *r,int a,int b)
{
    return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];
}
int c12(int k,int *r,int a,int b)
{
    if(k==2)
        return r[a]<r[b]||(r[a]==r[b]&&c12(1,r,a+1,b+1));
    else return r[a]<r[b]||(r[a]==r[b]&&wv[a+1]<wv[b+1]);
}
void sort(int *r,int *a,int *b,int n,int m)
{
    int i;
    for(i=0;i<n;i++) wv[i]=r[a[i]];
    for(i=0;i<m;i++) wss[i]=0;
    for(i=0;i<n;i++) wss[wv[i]]++;
    for(i=1;i<m;i++)wss[i]+=wss[i-1];
    for(int i=n-1;i>=0;i--)
        b[--wss[wv[i]]]=a[i];
}
void dc3(int *r,int *sa,int n,int m)
{
    int i,j,*rn=r+n;
    int *san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;
    r[n]=r[n+1]=0;
    for(i=0;i<n;i++) if(i%3!=0)wa[tbc++]=i;
    sort(r+2,wa,wb,tbc,m);
    sort(r+1,wb,wa,tbc,m);
    sort(r,wa,wb,tbc,m);
    for(p=1,rn[F(wb[0])]=0,i=1;i<tbc;i++)
        rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
    if(p<tbc)dc3(rn,san,tbc,p);
    else for(i=0;i<tbc;i++) san[rn[i]]=i;
    for(i=0;i<tbc;i++) if(san[i]<tb)wb[ta++]=san[i]*3;
    if(n%3==1)wb[ta++]=n-1;
    sort(r,wb,wa,ta,m);
    for(i=0;i<tbc;i++)wv[wb[i]=G(san[i])]=i;
    for(i=0,j=0,p=0;i<ta&&j<tbc;p++)
        sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
    for(;i<ta;p++)sa[p]=wa[i++];
    for(;j<tbc;p++)sa[p]=wb[j++];
}
void da(int str[],int sa[],int ra[],int height[],int n,int m)
{
	for(int i=n;i<3*n;i++)
        str[i]=0;
    dc3(str,sa,n+1,m);
	int i,j,k=0;
	for(int i=0;i<=n;i++) ra[sa[i]]=i;

	for(int i=0;i<n;i++)
	{
		if(k) k--;
		int j=sa[ra[i]-1];
		while(str[i+k]==str[j+k])k++;
		height[ra[i]]=k;
	}
}

int m,n,k,t;
int ra[maxn*3],height[maxn*3],str[maxn*3],sa[maxn*3];

char s[maxn];
int book[maxn]={0};
#include<vector>
vector<int>ans[maxn];
int main()
{
    scanf("%s",s);
    n=strlen(s);
    m=n;
    for(int i=0;i<n;i++)
    str[i]=s[i]-'a'+1;
    for(int i=n;i<n*2;i++)
        str[i]=str[i-n];
    n*=2;
    str[n]=0;
    da(str,sa,ra,height,n,30);

    int num=0;
    for(int i=0;i<m;i++)
    if(!book[i])
    {
        ans[++num].push_back(i);
        int k=ra[i];
        while(k-1>=1&&sa[k-1]<=m&&height[k]>=m)
        {
            k--;
            if(sa[k]==m) continue;
            book[sa[k]]=1;
            ans[num].push_back(sa[k]);
        }
        k=ra[i];
        while(k+1<n&&sa[k+1]<=m&&height[k+1]>=m)
        {
            k--;
            if(sa[k]==m) continue;
            book[sa[k]]=1;
            ans[num].push_back(sa[k]);
        }
    }

    printf("%d\n",num);
    for(int i=1;i<=num;i++)
    {
        printf("%d",ans[i].size());
        sort(ans[i].begin(),ans[i].end());
        for(int j=0;j<ans[i].size();j++)
            printf(" %d",ans[i][j]);
        puts("");
    }

	return 0;
}

kmp的算法

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int net[maxn],flag;
void kmp_pre(char x[],int m)
{
    int i,j;
    j=net[0]=-1;
    i=0;
    while(i<m)
    {
        while(j>-1&&x[i]!=x[j])
            j=net[j];
        net[++i]=++j;
    }

    if(m%(m-net[m])==0&&net[m]>0)//找寻环节
        flag=m-net[m];
}
int n;
char s[maxn];
int main()
{
    scanf("%s",s);
    n=strlen(s);
    flag=0;
    kmp_pre(s,n);
    if(flag)
    {
        printf("%d\n",flag);
        int num=n/flag;
        for(int i=0;i<flag;i++)
        {
            printf("%d",num);
            for(int j=i;j<n;j+=flag)
                printf(" %d",j);
            puts("");
        }
    }
    else //否则都不是同一组
    {
        printf("%d\n",n);
        for(int i=0;i<n;i++)
            printf("1 %d\n",i);
    }
    return 0;
}

比赛时过题的hash哈希

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int maxn=2e6+10;
ll p[maxn],ha[maxn];
const ll bas=31;
char s[maxn];
int n;
ll findha(int l,int r)
{
    return ha[r]-ha[l-1]*p[r-l+1];
}
struct node{
    int id;
    ll w;
}ma[maxn];
struct node1{
    int fi;
    vector<int>a;
}ans[maxn];
bool cmp(const node &a,const node &b)
{
    if(a.w==b.w) return a.id<b.id;
    return a.w<b.w;
}
bool cp(const node1 &a,const node1 &b)
{
    return a.fi<b.fi;
}
int main()
{
    scanf("%s",s);
    n=strlen(s);
    for(int i=n;i<n+n;i++)
        s[i]=s[i-n];
    n*=2;
    p[0]=1;
    for(int i=1;i<=n;i++)
    {
        p[i]=p[i-1]*bas;
        ha[i]=(ha[i-1]*bas+s[i-1]-'a'+1);
    }
    int m=n/2;
    for(int i=1;i<=m;i++)
    {
        ll tmp=findha(i,i+m-1);
        ma[i].id=i-1;
        ma[i].w=tmp;
    }
    sort(ma+1,ma+m+1,cmp);
    int num=0;
    for(int i=1;i<=m;i++)
    {
        if(ma[i].w!=ma[i-1].w)
        {
            num++;
            ans[num].fi=ma[i].id;
        }
        else ans[num].a.push_back(ma[i].id);
    }
    sort(ans+1,ans+num+1,cp);
    printf("%d\n",num);
    for(int i=1;i<=num;i++)
    {
        printf("%d",ans[i].a.size()+1);
        printf(" %d",ans[i].fi);
        for(int j=0;j<ans[i].a.size();j++)
            printf(" %d",ans[i].a[j]);
        puts("");
    }
    return 0;
}

 

AN-94 想要带着 AK-12 和指挥官你征战 XCPC。而现在,她正在学习后缀数组(Suffix Array,SA)。 由于她还是小白,因此她系统性学习了如下定义: 一个字符串 A 是另一个字符串 B 的后缀,当且仅当将 B 开头的若干字符删去后能得到 A 。例如:aba 是 ababa 的后缀,因为 ababa 删去开头的两个字符后可以得到 aba ;而 aba 不是 ababc 的后缀,因为无论删去 ababc 开头的少个字符,都无法得到 aba 。特别地,空串是所有字符串的后缀,不过一般不讨论,下文中所有后缀均指非空后缀。 对于字符串 A ,其以第 i 个字符开始的后缀编号为 i 。例如,对于字符串 aba ,编号为 1 的后缀为 aba ,编号为 2 的后缀为 ba , 编号为 3后缀为 a 。 后缀数组一般直接指 sa 数组,其第 i 项 sai 表示将所有后缀按照字典序大小排序后第 i 小的后缀的编号。 AN-94 觉得定义好复杂,不过她还是基本看懂了。她想让指挥官你写一个简单的程序来求出 sa 数组来帮助她加深理解。你能帮助她吗? 输入 输入一行一个字符串 s ,其长度 n 满足 n 为正整数且 1≤n≤500 ,保证 s 仅由小写字母组成。 输出 输出一行 n 个正整数,分别表示 sa 数组的第 1∼n 项,以空格隔开。 输入样例 1 ababa 输出样例 1 5 3 1 4 2 样例解释 1 ababa 编号为 1 的后缀为 ababa ,编号为 2 的后缀为 baba ,编号为 3后缀为 aba ,编号为 4 的后缀为 ba ,编号为 5 的后缀为 a 。 将它们按照字典序从小到大排序后为:a,aba,ababa,ba,baba ,对应的编号即为 5,3,1,4,2 。#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdbool.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <limits.h> //宏:定义 #define EPS 1e-9 #define MOD 100000000 //宏:类型 #define in int #define ll long long #define fl float #define db double #define ch char #define vd void //宏:函数 #define sc scanf #define pr printf //宏:输入 #define sc_in(x) sc("%d", &(x)) #define sc_ll(x) sc("%lld", &(x)) #define sc_db(x) sc("%lf", &(x)) #define sc_ch(x) sc("%c", &(x)) #define sc_st(str) sc("%s", (str)) //宏:输出(无换行) #define pr_in(x) pr("%d", x) #define pr_ll(x) pr("%lld", x) #define pr_db(x) pr("%lf", x) #define pr_ch(x) pr("%c", x) #define pr_st(x) pr("%s", x) //宏:输出(有换行) #define pr_inn(x) pr("%d\n", x) #define pr_lln(x) pr("%lld\n", x) #define pr_dbn(x) pr("%lf\n", x) #define pr_chn(x) pr("%c\n", x) #define pr_stn(x) pr("%s\n", x) //浮点相等判断 #define feq(a, b) (fabs((a) - (b)) < EPS) //数组长度获取 #define ArrayNum(x) (sizeof(x)/sizeof(x[0])) //vd bubble_sort(db* arr, size_t n) //{ // if (arr == NULL || n < 2) // { // return; // } // for (size_t i = 0; i < n - 1; i++) // { // in swapped = 0; // for (size_t j = 0; j < n - i - 1; j++) // { // if (arr[j] > arr[j + 1]) // { // db temp = arr[j]; // arr[j] = arr[j + 1]; // arr[j + 1] = temp; // swapped = 1; // } // } // if (!swapped) // { // break; // } // } //} //vd print_arr1(db arr[], in n) //{ // for (in i = 0; i < n; i++) // { // if (!(feq(arr[i], 0))) // { // pr("%.4lf ", arr[i]); // } // // } //} //in main() //{ // in n; // sc_in(n); // db arr[2010] = { 0 }; // for (in i = 0; i < n; i++) // { // sc_db(arr[i]); // } // bubble_sort(arr, ArrayNum(arr)); // print_arr1(arr, ArrayNum(arr)); // return 0; //} //in main() //{ // in t; // sc_in(t); // while (t--) // { // in n; // sc_in(n); // in c[3] = { 0 }; // for (in i = 0; i < n; i++) // { // in a; // sc_in(a); // c[a % 3]++; // } // in max = c[0]; // if (c[1] > max) // { // max = c[1]; // } // if (c[2] > max) // { // max = c[2]; // } // if (max <= (n + 1) / 2) // { // pr("YES\n"); // } // else // pr("NO\n"); // } // return 0; //} //in main() //{ // in arr[110][2]; // in n, m; // sc_in(n); // sc_in(m); // in N = n; // for (in row = 1; row <= n; row++) // { // for (in col = 1; col <= 2; col++) // { // if (col == 1) // { // arr[row][col] = row; // } // else // { // arr[row][col] = 1; // } // } // } // in i = 0; // while (N >=1) // { // for (in row = 1; row <= n; row++) // { // if (arr[row][2] == 0) // { // i = i; // } // else // { // i++; // } // if (i % m == 0) // { // if (arr[row][2] != 0) // { // pr_in(row); // pr(" "); // N--; // } // arr[row][2] = 0; // } // } // } // return 0; //} //vd reverse_string1(ch* str) //{ // if (str == NULL) // { // return; // } // in left = 0; // in right = strlen(str) - 1; // ch temp; // while (left < right) // { // temp = str[left]; // str[left] = str[right]; // str[right] = temp; // left++; // right--; // } //} //ll pow_mod1(ll base, ll exp) //{ // ll result = 1; // while (exp > 0) // { // if (exp & 1) // { // result = (result * base); // } // base = (base * base); // exp >>= 1; // } // return result; //} //ch str[100000000]; //in main() //{ // in n; // sc_in(n); // for (in i = 0; i < n; i++) // { // in digit; // sc_st(str); // in flag = 1; // if (str[0] == &#39;-&#39;) // { // for (in i = 0; i < ArrayNum(str); i++) // { // str[i] = str[i + 1]; // } // flag = -1; // } // reverse_string1(str); // if (str[0] == &#39;a&#39;) // { // digit = 10; // } // else if (str[0] == &#39;b&#39;) // { // digit = 11; // } // else if (str[0] == &#39;c&#39;) // { // digit = 12; // } // else if (str[0] == &#39;d&#39;) // { // digit = 13; // } // else if (str[0] == &#39;e&#39;) // { // digit = 14; // } // else if (str[0] == &#39;f&#39;) // { // digit = 15; // } // else if (str[0] == &#39;g&#39;) // { // digit = 16; // } // else // { // digit = str[0] - &#39;0&#39;; // } // ll sum = 0; // ll base = 1; // for (ll i = 1; i <strlen(str); i++) // { // if(isalpha(str[i])) // { // sum += (str[i] - &#39;a&#39; + 11) * pow_mod1(digit, i - 1); // } // else // { // sum += (str[i]-&#39;0&#39;) * pow_mod1(digit, i - 1); // } // } // if (flag == -1) // { // printf("-"); // } // pr("%lld\n", sum); // } // return 0; //} //int main() //{ // ll AA[110][110] = { 0 }; // ll n; // scanf("%lld", &n); // for (int i = 1; i <= n; i++) // { // for (int j = 1; j <= n; j++) // { // scanf("%lld", &AA[i][j]); // } // } // for (int i = 1; i <= n; i++) // { // for (int j = 1; j <= n; j++) // { // printf("%lld ", AA[j][i] + AA[i][j]); // } // printf("\n"); // } // return 0; //} //ch index_name[1010][110]; //in main() //{ // for (in i = 1; i <= 1000; i++) // { // A: // ; // ch c; // in j = 0; // while ((c = getchar()) != &#39;\n&#39; && c != EOF) // { // index_name[i][j++] = c; // } // index_name[i][j] = &#39;\0&#39;; // if (c == EOF) // { // return 0; // } // for (in k = 1; k < i; k++) // { // if (strcmp(index_name[i], index_name[k]) == 0) // { // pr("Not Applicable\n"); // goto A; // } // } // pr("Delicious!\n"); // } // return 0; //} //vd bubble_sort1(in* arr, size_t n) //{ // if (arr == NULL || n < 2) // { // return; // } // for (size_t i = 0; i < n - 1; i++) // { // in swapped = 0; // for (size_t j = 0; j < n - i - 1; j++) // { // if (arr[j] > arr[j + 1]) // { // in temp = arr[j]; // arr[j] = arr[j + 1]; // arr[j + 1] = temp; // swapped = 1; // } // } // if (!swapped) // { // break; // } // } //} //vd scan_arr11(in arr[], in n) //{ // for (in i = 0; i < n; i++) // { // sc("%d", &arr[i]); // } //} // in arr[10010] = { 0 }; //in main() //{ // in n; // sc_in(n); // db p; // sc_db(p); // // scan_arr11(arr, n); // bubble_sort1(arr, n); // db P = n * p; // in Q = n * p; // if (feq(P, Q)) // { // db xp = 0.5 * (arr[Q - 1] + arr[Q]); // pr("%.1lf",xp); // } // else // { // in xp = arr[Q]; // pr("%d", xp); // pr(".0"); // } // return 0; //} //思路 //从后往前读字串可以保证长度的升序; //长度的升序,转换为检索的下标 //子串长度l = sizeof(str) - 字符串下标 //abcde; //e 长度1 index = 5;arr[5] = &#39;e&#39; - &#39;a&#39;=4; //d 长度2 index = 4;arr[4] = &#39;d&#39; - &#39;a&#39;=3; //ababa //a index = 5; arr[5] = 0; //b index = 4; arr[4] = 1; //a index = 3; arr[3] = 0; //b index = 2; arr[2] = 1; //a index = 1; arr[1] = 0; in arr[505]; in main() { ch c; in j = 1; while ((c = getchar()) != &#39;\n&#39; && c != EOF) { arr[j++] = c - &#39;a&#39; + 1; } in k = 1; while (k <= 26) { for (in i = j - 1; i >= 1; i--) { if (arr[i] == k) { pr("%d ", i); } } k++; } return 0; }
最新发布
11-01
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值