zoukankan      html  css  js  c++  java
  • P3975 [TJOI2015]弦论

    P3975 [TJOI2015]弦论

    一定要记得初始化!

    后缀链接连接的节点所表示的字符串是该节点表示字符串的后缀,先将所有新增节点的dp[i]都置为1(除了拆点),一个节点所表示字符串的出现次数是其子树所有dp值之和(下标不同,本质相同的两个串是不同串)

    如果下标不同,本质相同的两个串属于一个串的话,那么所有的dp[i]为1即可。因为,后缀树的所有节点包括了所有的子串。然后再按照Next转移即可。

    Next 表示的是转移,通过每个节点的转移,可以得到后缀树中的所有子串

    link 指向的是子串,所以 p 指向的节点一定会让 link[p] 表示的字符串在除 link[p] 表示的位置再出现一次。

    // Created by CAD
    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=1e6+10;
    namespace sam{
        int len[maxn],link[maxn],Next[maxn][26];
        int sz,last;
        int dp[maxn];
        void init(){                //记得初始化
            sz=last=0;
            len[0]=0,link[0]=-1;
        }
        void insert(char c){        //插入字符
            int now=++sz;
            len[now]=len[last]+1;
            int p=last;
            dp[now]=1;
            while(~p&&!Next[p][c-'a']){
                Next[p][c-'a']=now;
                p=link[p];
            }
            if(p==-1) link[now]=0;
            else{
                int q=Next[p][c-'a'];
                if(len[p]+1==len[q]) link[now]=q;
                else{
                    int clone=++sz;
                    len[clone]=len[p]+1;
                    memcpy(Next[clone],Next[q],sizeof(Next[q]));
                    link[clone]=link[q];
                    while(~p&&Next[p][c-'a']==q){
                        Next[p][c-'a']=clone;
                        p=link[p];
                    }
                    link[q]=link[now]=clone;
                }
            }
            last=now;
        }
        vector<int> g[maxn];
        int dfs(int x){                     //预处理出每一个节点表示串的出现次数
            for(int i:g[x])
                dp[x]+=dfs(i);
            return dp[x];
        }
        bool vis[maxn];
        int sum[maxn];
        int dfs2(int x){                    //预处理出每一个节点其子树的贡献和
            if(vis[x]) return sum[x];vis[x]=1;
            for(int i=0;i<26;++i){
                int o=Next[x][i];
                if(o)   sum[x]+=dfs2(o);
            }
            return sum[x];
        }
        void out(int x,int k){
            if(dp[x]>=k) return;            //扣除该节点的贡献
            k-=dp[x];
            for(int i=0;i<26;++i){
                int o=Next[x][i];
                if(!o) continue;
                else if(sum[o]<k) k-=sum[o];//如果子节点的贡献比当前k小,那么扣除子节点的贡献
                else{                       //如果大于,说明当前节点或者当前节点的子树包括了第k小
                    printf("%c",'a'+i);
                    out(o,k);
                    return ;
                }
            }
        }
        void solve(int t,int k){
            for(int i=1;i<=sz;++i)
                g[link[i]].push_back(i);
            dfs(0);
            for(int i=0;i<=sz;++i)
                sum[i]=t?dp[i]:(dp[i]=1);
            dp[0]=sum[0]=0;
            if(dfs2(0)<k) return puts("-1"),void();
            out(0,k);
        }
    }
    char s[maxn];
    int main() {
        scanf("%s",s);
        int t,k;scanf("%d%d",&t,&k);
        sam::init();
        int n=strlen(s);
        for(int i=0;i<n;++i) sam::insert(s[i]);
        sam::solve(t,k);
        return 0;
    }
    
  • 相关阅读:
    Overloaded的方法是否可以改变返回值的类型
    parseXXX的用法
    java的类型转换问题。int a = 123456;short b = (short)a;System.out.println(b);为什么结果是-7616?
    UVA 10405 Longest Common Subsequence(简单DP)
    POJ 1001 Exponentiation(大数处理)
    POJ 2318 TOYS(计算几何)(二分)
    POJ 1265 Area (计算几何)(Pick定理)
    POJ 3371 Flesch Reading Ease (模拟题)
    POJ 3687 Labeling Balls(拓扑序列)
    POJ 1094 Sorting It All Out(拓扑序列)
  • 原文地址:https://www.cnblogs.com/CADCADCAD/p/13522292.html
Copyright © 2011-2022 走看看