sgu232(最小表示法)

来源:互联网 发布:杭州10月份房产数据 编辑:程序博客网 时间:2024/05/29 19:54

题意:

给出n,m,以及长度为n的原字符串S[0,n-1]。根据S构造出新的n个字符串A[n],A[i][j]=S[(i+j*m)%n]。求A中最大的串。

tip:

尝试nm之后 可以发现a每n次开始循环(mod后和之前的循环节是同样的几个数,可能不到n),每次由于是取mod 所以也是有循环节的,那么找出这个循环节,找到循环同构中最大的(左移或右移任意位)就可以。。。

最小表示法:
例如,字符串”abcd”的循环同构字符串有:[“abcd”, “bcda”, “cdab”, “dabc”]。
题目的目标是求这些字符串中字典序最小的那个 算法描述 :

令i=0,j=1如果S[i] > S[j] i=j, j=i+1如果S[i] < S[j] j++如果S[i] == S[j] 设指针k,分别从i和j位置向下比较,直到S[i] != S[j]         如果S[i+k] > S[j+k] I+= k+1 ,k = 0,//(j变为标准)         否则 j+=k+1,k = 0  //(i仍是标准)if(I == j)j++;返回min(i,j)

类似双支针,一直保留较小的一个。。比较好理解,最大表示除了比较的大于小于变一下就好了

int maxrp(string s){    int Len = s.length(),l = 0,r = 1,k = 0;    while(l < Len && r < Len && k < Len){        int a1 = s[(l+k)%Len] ,a2 = s[(r+k)%Len];        if(a1 == a2)    k++;        else if(a1 < a2){            l+= k+1;            k = 0;        }        else {            r += k+1;k = 0;        }        if(l == r)  r++;    }    return min(l,r);}

整个题的代码:

#include <cstdio>#include <iostream>#include <cstring>#include <string>using namespace std;string s,ans = "";const int maxn = 150010;int len,vis[maxn];int n,m;void init(){    scanf("%d%d",&n,&m);    cin >> s;    len = s.length();}int maxrp(string s){    int Len = s.length(),l = 0,r = 1,k = 0;    while(l < Len && r < Len && k < Len){        int a1 = s[(l+k)%Len] ,a2 = s[(r+k)%Len];        if(a1 == a2)    k++;        else if(a1 < a2){            l+= k+1;            k = 0;        }        else {            r += k+1;k = 0;        }        if(l == r)  r++;    }    return min(l,r);}void sov(){    int cnt = 0;    for(int i = 0 ; i < len ; i++){        if(vis[i])  continue;        string tmp = "";        cnt++;        int j = i;        while(1){            if(vis[j] == cnt)    break;            vis[j] = cnt;            tmp.push_back(s[j]);            j = (j+m)%n;        }        int pos = maxrp(tmp),Len = tmp.length();        tmp += tmp;        string pp = tmp.substr(pos,Len);        if(ans == "" || ans < pp)   ans = pp;    }    string nn = "";    int k = ans.length();    int rp = n/k;    for(int i = 1; i <= rp ; i++)        nn += ans;    int mo = n-nn.length();    nn = nn+nn.substr(0,mo);    cout <<nn<<endl;}int main(){    //ios::sync_with_stdio(false);    init();    sov();}
原创粉丝点击