hihocold #1466 : 后缀自动机六·重复旋律9

这道题目自己傻傻的写拓扑排序写错了,直接写成了,细节MAX
这里在贴一个别人的好代码

Mine:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=500010,Max_SG=26;
char str[N],ansA[N],ansB[N];
int lena,lenb;

struct SAM{
    int last,root,cnt,tim;
    int fa[N],c[N][26],len[N],SG[N],q[N],in[N];
    LL dp[N][27],sum[N];
    bool vis[N];
    void init()
    {last=root=++cnt;}
    void extend(int x)
    {
        int p=last,np=last=++cnt;
        len[np]=len[p]+1;
        while (p && !c[p][x])
            c[p][x]=np,p=fa[p];
        if (!p) fa[np]=root;
        else
        {
            int q=c[p][x];
            if (len[q]==len[p]+1)
                fa[np]=q;
            else
            {
                int nq=++cnt;
                len[nq]=len[p]+1;
                memcpy(c[nq],c[q],sizeof(c[q]));
                fa[nq]=fa[q];
                fa[q]=fa[np]=nq;
                while (p && c[p][x]==q)
                    c[p][x]=nq,p=fa[p];
            }
        }
    }
    void insert(char *str)
    {
        init();
        int len=strlen(str);
        for (int i=0;i<len;i++)
            extend(str[i]-'a'); 
    }
    void calc_SG_dp()
    {
        int l=1,r=1;
        for (int i=1;i<=cnt;i++)
            for (int j=0;j<26;j++)
                if (c[i][j]) in[c[i][j]]++;
        for (int i=1;i<=cnt;i++)
            if (!in[i]) q[r++]=i;
        while (l<r)
        {
            int u=q[l++];
            for (int i=0;i<26;i++)
            {
                int v=c[u][i];
                if (!v) continue;
                in[v]--;
                if (!in[v]) q[r++]=v;
            }
        }
        for (int i=cnt;i>=1;i--)
        {
            int u=q[i];
            for (int j=0;j<=Max_SG;j++) vis[j]=false;
            for (int j=0;j<26;j++)
                if (c[u][j]) vis[SG[c[u][j]]]=true;
            SG[u]=0;
            while (vis[SG[u]]) SG[u]++;
        }
        for (int i=cnt;i>=1;i--)
        {
            int u=q[i];
            dp[u][SG[u]]=1;
            for (int j=0;j<26;j++)
            {
                if (!c[u][j]) continue;
                int v=c[u][j];
                for (int k=0;k<=Max_SG;k++)
                    dp[u][k]+=dp[v][k];
            }
            for (int k=0;k<=Max_SG;k++) sum[u]+=dp[u][k];
        }
    }
}A,B;

void solve(LL K)
{
    lena=lenb=0;
    int nowa=1,nowb=1;
    while (true)
    {
        bool flag=true;
        int sg=A.SG[nowa];
        LL tmp=B.sum[1]-B.dp[1][sg];
        if (tmp>=K) break;
        K-=tmp;
        for (int i=0;i<26;i++)
        {
            if (!A.c[nowa][i]) continue;
            int u=A.c[nowa][i];
            LL tmp=0;
            for (int j=0;j<=Max_SG;j++)
                tmp+=(B.sum[1]-B.dp[1][j])*A.dp[u][j];
            if (tmp<K) K-=tmp;
            else
            {
                nowa=u;
                flag=false;
                ansA[lena++]=i+'a';
                break;
            }
        }
        if (flag) {puts("NO");return;}
    }
    for (int i=0;i<lena;i++) putchar(ansA[i]); puts("");    
    int sg=A.SG[nowa];
    while (K>0)
    {
        int sgB=B.SG[nowb];
        if (sgB!=sg) K--;
        if (!K) break;
        for (int i=0;i<26;i++)
        {
            int v=B.c[nowb][i];
            if (!v) continue;
            LL tmp=B.sum[v]-B.dp[v][sg];
            if (tmp<K) K-=tmp;
            else 
            {
                nowb=v;
                ansB[lenb++]=i+'a';
                break;
            }
        }
    }
    for (int i=0;i<lenb;i++) putchar(ansB[i]); puts("");    
}

int main()
{
    LL K;
    scanf("%lld",&K);
    scanf("%s",str);
    A.insert(str);
    A.calc_SG_dp();
    scanf("%s",str);
    B.insert(str);
    B.calc_SG_dp();
    solve(K);
    return 0;
}

and good:


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100005
#define N 200005
#define LL long long
using namespace std;
struct SAM{
    int n,ch[N][26],sg[N],fr[N],len[N],tot;
    LL cnt[N][28];
    char S[M];
    void NewNode(int &p,int d,int pl,int f){
        p=++tot;
        len[p]=d,fr[p]=f;
        if(pl==-1)for(int i=0;i<26;i++)ch[p][i]=-1;
        else for(int i=0;i<26;i++)ch[p][i]=ch[pl][i];
    }
    void Addchar(int u,int &p,int c){
        NewNode(p,len[u]+1,-1,-1);
        int v=u;
        while(v!=-1&&ch[v][c]==-1){
            ch[v][c]=p;
            v=fr[v];
        }
        if(v==-1){
            fr[p]=0;
            return;
        }
        int x=ch[v][c],y;
        if(len[x]==len[v]+1){
            fr[p]=x;
            return;
        }
        NewNode(y,len[v]+1,x,fr[x]);
        fr[x]=fr[p]=y;
        while(v!=-1&&ch[v][c]==x){
            ch[v][c]=y;
            v=fr[v];
        }
    }
    int dfs(int x){
        if(sg[x]!=-1)return sg[x];
        bool ct[27];
        for(int i=0;i<27;i++)ct[i]=0;
        for(int i=0;i<26;i++){
            int to=ch[x][i];
            if(to==-1)continue;
            ct[dfs(to)]=1;
            for(int j=0;j<27;j++)cnt[x][j]+=cnt[to][j];
        }
        for(int i=0;i<27;i++)if(!ct[i]){sg[x]=i;break;}
        cnt[x][sg[x]]++;
        for(int i=0;i<27;i++)cnt[x][27]+=cnt[x][i];
        return sg[x];
    }
    void Init(){
        for(int i=0;i<26;i++)ch[0][i]=-1;fr[0]=-1;
        int u=0;
        for(int i=1;i<=n;i++)Addchar(u,u,S[i]-'a');
        memset(sg,-1,sizeof(sg));
        dfs(0);
    }
    void Pr(){
        for(int i=0;i<=tot;i++){
            printf("i:%d : ",i);
            for(int j=0;j<28;j++)printf("%d ",cnt[i][j]);
            printf("sg::%d\n",sg[i]);
        }
    }
}A,B;
LL k;
char ans[2][M];
LL cost(int u,int v){
    LL res=0;
    for(int i=0;i<27;i++)
        res+=1LL*A.cnt[u][i]*(B.cnt[v][27]-B.cnt[v][i]);
    return res;
}
int dfs(int p,int x){
    LL ct=B.cnt[0][27]-B.cnt[0][A.sg[x]];
    if(k<=ct)return x;
    else k-=ct;
    for(int i=0;i<26;i++){
        int to=A.ch[x][i];
        if(to==-1)continue;
        LL pl=cost(to,0);
        if(pl<k)k-=pl;
        else {
            ans[0][p]='a'+i;
            return dfs(p+1,to);
        }
    }return -1;
}
void rdfs(int p,int x,int T){
    k-=A.sg[T]!=B.sg[x];
    if(k==0)return;
    for(int i=0;i<26;i++){
        int to=B.ch[x][i];
        if(to==-1)continue;
        LL pl=B.cnt[to][27]-B.cnt[to][A.sg[T]];
        if(pl<k)k-=pl;
        else {
            ans[1][p]='a'+i;
            rdfs(p+1,to,T);
            return;
        }
    }
}
int main(){


//int size = 32 << 20; // 32MB
//char *p = (char*)malloc(size) + size;
//__asm__("movl %0, %%esp\n" :: "r"(p));

//  freopen("in.in","r",stdin);
//  freopen("1.out","w",stdout);
    cin>>k;scanf("%s%s",A.S+1,B.S+1);
    A.n=strlen(A.S+1);B.n=strlen(B.S+1);
    A.Init();B.Init();
    int T=dfs(0,0);
    if(T==-1){printf("NO");return 0;}
    rdfs(0,0,T);
    puts(ans[0]);puts(ans[1]);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值