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

    题目描述

    为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?

    输入格式

    第一行是一个仅由小写英文字母构成的字符串s

    第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。

    输出格式

    输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-1。

    输入输出样例

    输入 #1

    aabc
    0 3
    

    输出 #1

    aab
    

    输入 #2

    aabc
    1 3
    

    输出 #2

    aa
    

    输入 #3

    aabc
    1 11
    

    输出 #3

    -1
    

    说明/提示

    数据范围

    对于10%的数据,n ≤ 1000。

    对于50%的数据,t = 0。

    对于100%的数据,n ≤ 5 × 10^5, t < 2, k ≤ 10^9。

    其实我对sam还不是很透彻只是似懂非懂

    只放代码吧

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N = 2e6+5; // 两倍空间 , 一次插入可能产生两个节点
    int n , tot = 1 , las = 1;
    int len[N] , fa[N] , tr[N][26] , a[N] , t[N];
    long long siz[N] , sum[N];
    char c[N];
    
    void Insert(int c) // 板子又一次出锅
    {
    	int cur = ++tot , p = las; len[cur] = len[las] + 1; las = cur; siz[cur] = 1;
    	for( ; p && tr[p][c] == 0 ; p = fa[p]) tr[p][c] = cur;
    	if(p == 0) fa[cur] = 1;
    	else
    	{
    		int q = tr[p][c];
    		if(len[q] == len[p] + 1) fa[cur] = q;
    		else
    		{// 这里的nq的siz不能设为 1
    			int nq = ++tot;/*siz[tot] = 1;*/ fa[nq] = fa[q]; len[nq] = len[p] + 1;
    			for(int i = 0 ; i < 26 ; ++i) tr[nq][i] = tr[q][i];
    			fa[cur] = fa[q] = nq;
    			for( ; p && tr[p][c] == q ; p = fa[p]) tr[p][c] = nq;
    		}
    	}
    }
    
    int main()
    {
    	scanf("%s",c+1); n = strlen(c+1);
    	int T , K; scanf("%d %d" , &T , &K);
    	for(int i = 1 ; i <= n ; ++i) Insert(c[i] - 'a');
    	for(int i = 1 ; i <= tot ; ++i) t[len[i]]++;
    	for(int i = 1 ; i <= tot ; ++i) t[i] += t[i-1];
    	for(int i = 1 ; i <= tot ; ++i) a[t[len[i]]--] = i;
    	// tr 与 fa 并不是一个东西 , 
    	// tr 表示在这个状态后加上 i 会到达的状态 , 
    	// fa 是后缀中第一个endpos不同于它本身的后缀的状态
    	for(int i = tot ; i >= 1 ; --i) 
    	{
    		int x = a[i];
    		if(T == 1) siz[fa[x]] += siz[x];
    		else siz[x] = 1;
    	}
    	siz[1] = 0;
    	for(int i = tot ; i >= 1 ; --i)
    	{
    		int x = a[i]; sum[x] = siz[x];
    		for(int j = 0 ; j < 26 ; ++j)
    			if(tr[x][j]) sum[x] += sum[tr[x][j]];
    	}
    	if(sum[1] < K) puts("-1");
    	else
    	{
    		int now = 1; K -= siz[now];
    		while(K > 0)
    		{
    			int i = 0;
    			while(K > sum[tr[now][i]])
    			{
    				K -= sum[tr[now][i]];
    				i++;
    			}
    			now = tr[now][i]; putchar(i + 'a');
    			K -= siz[now];
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    小程序实现删除列表某条内容的功能
    关于多行文本 textarea 在ios 真机上padding相对安卓较大问题
    关于小程序 input 组件内容显示不全(显示的长度不满 input 宽度)问题
    关于小程序button控件上下边框的显示和隐藏问题
    关于微信小程序 textarea组件在fixed定位的模块中随页面移动问题
    首记
    java >>> 和 >>>=的区别
    Nginx" upstream prematurely closed connection while reading response header from upstream"问题排查
    nginx配置rewrite总结
    nginx配置location总结
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12150381.html
Copyright © 2011-2022 走看看