• P3975 [TJOI2015]弦论


    思路

    一眼SAM板子,结果敲了一中午。。。
    我还是太弱了
    题目要求求第k小的子串
    我们可以把t=0当成t=1的特殊情况,(所有不同位置的相同子串算作一个就是相当于把所有子串的出现位置个数(endpos大小)全部赋成1)
    然后讨论如何递推的求第k小的子串
    首先要统计一个sum值,代表从这个状态出发能够到达多少个子串,相当于这个节点后继节点的所有值的和,反向拓扑一下能到那些节点即可
    然后逐个dfs每个位置的字符是什么即可

    注意

    反向拓扑不一定要真的反向建边(狗头),我这么乱搞了。。。
    可以把每个点的maxlen从小到大基数排序一发,然后正向拓扑就是从小到大,反向就是从大到小
    会快很多

    因为乱搞只能开O2过的代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <vector>
    #define int long long 
    const int MAXN = 500100*2;
    using namespace std;
    int trans[MAXN][26],suflink[MAXN],endpos[MAXN],maxlen[MAXN],minlen[MAXN],Nodecnt,ispre[MAXN],in[MAXN],sum[MAXN];
    char s[MAXN],ans[MAXN];
    int new_state(int _maxlen,int _minlen,int *_trans,int _suflink){
        ++Nodecnt;
        maxlen[Nodecnt]=_maxlen;
        minlen[Nodecnt]=_minlen;
        if(_trans)
            for(int i=0;i<26;i++)
                trans[Nodecnt][i]=_trans[i];
        suflink[Nodecnt]=_suflink;
        return Nodecnt;
    }
    int add_len(int u,int c){
        int z=new_state(maxlen[u]+1,0,NULL,0);
        ispre[z]=1;
        while(u&&trans[u][c]==0){
            trans[u][c]=z;
            u=suflink[u];
        }
        if(!u){
            suflink[z]=1;
            minlen[z]=1;
            return z;
        }
        int v=trans[u][c];
        if(maxlen[v]==maxlen[u]+1){
            suflink[z]=v;
            minlen[z]=maxlen[v]+1;
            return z;
        }
        int y=new_state(maxlen[u]+1,0,trans[v],suflink[v]);
        suflink[v]=suflink[z]=y;
        minlen[v]=minlen[z]=maxlen[y]+1;
        while(u&&trans[u][c]==v){
            trans[u][c]=y;
            u=suflink[u];
        }
        minlen[y]=maxlen[suflink[y]]+1;
        return z;
    }
    queue<int> q;
    void topu_size(int tx){
        for(int i=1;i<=Nodecnt;i++) 
            in[suflink[i]]++;
        for(int i=1;i<=Nodecnt;i++)
            if(!in[i])
                q.push(i);
        while(!q.empty()){
            int x=q.front();
            q.pop();
            endpos[x]+=ispre[x];
            endpos[suflink[x]]+=endpos[x];
            in[suflink[x]]--;
            if(!in[suflink[x]])
                q.push(suflink[x]);
        }
    }
    int u[MAXN*10],v[MAXN*10],fir[MAXN*10],nxt[MAXN*10],cnt;
    void addedge(int ui,int vi){
        ++cnt;
        u[cnt]=ui;
        v[cnt]=vi;
        nxt[cnt]=fir[ui];
        in[vi]++;
        fir[ui]=cnt;
    }
    void topu_sum(int tx){
        for(int i=1;i<=Nodecnt;i++){
            for(int j=0;j<26;j++)
                if(trans[i][j]){
                    addedge(trans[i][j],i);
                }
            if(tx==0){
                endpos[i]=sum[i]=1;
            }
            else{
                sum[i]=endpos[i];
            }
        }
        sum[1]=endpos[1]=0;
        for(int i=1;i<=Nodecnt;i++)
            if(!in[i])
                q.push(i);
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=fir[x];i;i=nxt[i]){
                sum[v[i]]+=sum[x];
                in[v[i]]--;
                if(!in[v[i]])
                    q.push(v[i]);
            }
        }
    }
    int k,t,n;
    int dfs(int pos,int x,int tx){
        // printf("pos=%lld x=%lld k=%lld
    ",pos,x,k);
        if(k<=endpos[x])
            return 1;
        k-=endpos[x];
        for(int i=0;i<26;i++){
            if(!trans[x][i])
                continue;
            // printf("gg %d
    ",trans[x][i]);
            int mid=sum[trans[x][i]];
            if(k>mid)
                k-=mid;
            else{
                // printf("to %d
    ",trans[x][i]);
                // k-=endpos[trans[x][i]];
                ans[pos]='a'+i;
                return dfs(pos+1,trans[x][i],tx);
            }
        }
        return -1;
    }
    signed main(){
        freopen("1.in","r",stdin);
        scanf("%s",s+1);
        scanf("%lld %lld",&t,&k);
        n=strlen(s+1);
        Nodecnt=1;
        int pre=1;
        for(int i=1;i<=n;i++)
            pre=add_len(pre,s[i]-'a');
        // printf("ok
    ");
        topu_size(t);
        topu_sum(t);
        // for(int i=1;i<=Nodecnt;i++)
        //     printf("maxlen=%lld minlen=%lld endpos=%lld suflink=%lld sum=%lld
    ",maxlen[i],minlen[i],endpos[i],suflink[i],sum[i]);
        int req=dfs(1,1,t);
        if(req==-1){
            printf("-1
    ");
            return 0;
        }
        printf("%s
    ",ans+1);
        return 0;
    }
    
    
  • 相关阅读:
    SpringBoot的@Import和@ImportResource
    SpringBoot引入其他配置文件
    SpringBoot加载application.properties配置文件的顺序
    Interceptor(拦截器)
    Filter(过滤器)
    ES6数组知识点,巧妙运用数组,对循环说88
    javase基础socket编程之局域网聊天,局域网文件共享
    【金三银四】缓存面试题-web层缓存
    MD5和SHA-1加密算法被我国密码学家王小云破解
    java中的ArrayList 的C语言实现版本。
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10516460.html
Copyright © 2020-2023  润新知