• 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;
    }
    
    
  • 相关阅读:
    Linux下通过Generic Binaries安装MySQL 5.5
    struts 2 中AJAX的使用及Struts 2 JSON的使用
    关于Abstract interface的问题。
    对于“Win8对开发者的影响”的一些看法
    RealtimeModifier Bug Report | RealtimeModifier Bug 反馈
    何为Tomcat内存
    SSH开发过程中的中文问题汇总
    Spring Test 整合 JUnit 4 使用总结
    创建Shell脚本方便MySQL服务端启动
    学习笔记 winForm move功能 与 drag 功能
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10516460.html
Copyright © 2020-2023  润新知