UVA 10829 L-Gap Substrings

题意:

形如UVU这种字符串,其中U、V都是字符串,V的长度为L,那么称此种字符串为L-Gap String,要求的是一个字符串中有多少个子串为L-Gap String。

题解:

网上有很多关于此题的题解,但是都只是说了怎么做的,并没有说为什么是这样。

开始其实也不懂,后面写出来就好像懂了。

大概说一下思路,首先用后缀数组求出lcp是很容易想到的,

我们可以每次枚举U的长度L,那么就可以得到一个区间[i,i+L+G],这里的G是UVU中V的长度,

每次的长度G就只从此区间中取,就可以避免重复计算答案,

如果区间[i,i+L+G]的lcp的长度大于等于L是不是就一种可能,至于大于L就看成L就可以了,因为要保证G在区间内,但是这里i怎么办,直接枚举肯定会TLE,

假设当前L为4,G为1,i为5,在计算区间[5,10]时,如果i每次直接移动L,其实在区间[5+j,10-j],j<=L是没有计算的,如果将这段没计算的区间计算出来,那么i就可以移动L复杂度为nlogn,那么时间就没问题了,

问题其实就相当于求出5~0和10~0的公共前缀,那么就可以求出j为多少,即可以求出U长度为L,间隔为G的方案种数,

因为假设[i,i+L+G]的公共前缀为X<=L,那么j可以向前移动Y次(相当于i-Y和i+L+G-Y的前缀为Y),那么他们的总前缀长度为X+Y,枚举U的长度为L,所以方案数为X+Y-L+1。

求5~0和10~0的公共前缀就可以通过反转求后缀数组,不就可以求出最长公共前缀了。

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <utility>
#include <map>
#include <set>
#include <queue>
#include <vector>
#include <iostream>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-6
#define CLR( a, v ) memset ( a, v, sizeof ( a ) )
#define LL long long
#define DBUG printf ( "here!!!" )
#define rep( i, a, b ) for ( int i = ( a ); i < ( b ); i ++ )
#define PB push_back
#define ULL unsigned long long
#define PI acos ( -1.0 )
#define lson l, m, rt << 1
#define rson m+1, r, rt << 1 | 1
#define lowbit( x ) ( ( x )&( -x ) )
typedef pair < int, int > Pii;
typedef pair < double, double > Pdd;
const int maxn = 50005*4;
int read_int ( )
{
    int res = 0;
    int ch;
    while ( ( ch = getchar ( ) ) && ! ( ch >= '0' && ch <= '9' ) )
    {
        if ( ch == -1 )
            return -1;
    }
    while ( ch >= '0' && ch <= '9' )
    {
        res = res*10+( ch-'0' );
        ch = getchar ( );
    }
    return res;
}
char str[maxn];
int t1[maxn], t2[maxn], rk[maxn], sa[maxn];
int lcp[maxn], cnt[maxn];
void build_sa ( int n, int m )
{
    int * x = t1, * y = t2;
    for ( int i = 0; i < m; i ++ )
        cnt[i] = 0;
    for ( int i = 0; i < n; i ++ )
        cnt[ x[i] = str[i] ] ++;
    for ( int i = 1; i < m; i ++ )
        cnt[i] += cnt[i-1];
    for ( int i = n-1; i >= 0; i -- )
        sa[ --cnt[ x[i] ] ] = i;
    for ( int k = 1; k <= n; k <<= 1 )
    {
        int p = 0;
        for ( int i = n-k; i < n; i ++ )
            y[p ++] = i;
        for ( int i = 0; i < n; i ++ )
            if ( sa[i] >= k )
                y[p ++] = sa[i]-k;
        for ( int i = 0; i < m; i ++ )
            cnt[i] = 0;
        for ( int i = 0; i < n; i ++ )
            cnt[ x[ y[i] ] ] ++;
        for ( int i = 1; i < m; i ++ )
            cnt[i] += cnt[i-1];
        for ( int i = n-1; i >= 0; i -- )
            sa[ --cnt[ x[ y[i] ] ] ] = y[i];
        swap ( x, y );
        x[ sa[0] ] = 0;
        p = 1;
        for ( int i = 1; i < n; i ++ )
            x[ sa[i] ] = y[ sa[i-1] ] == y[ sa[i] ] &&
                        y[ sa[i-1]+k ] == y[ sa[i]+k ] ? p-1 : p ++;
        if ( p >= n )
            break ;
        m = p;
    }
}
void build_lcp ( int n )
{
    for ( int i = 0; i <= n; i ++ )
        rk[ sa[i] ] = i;
    int h = 0;
    lcp[0] = 0;
    for ( int i = 0; i < n; i ++ )
    {
        int j = sa[ rk[i]-1 ];
        if ( h )    h --;
        while ( j+h < n && i+h < n )
        {
            if ( str[j+h] != str[i+h] )
                break ;
            h ++;
        }
        lcp[ rk[i] ] = h;
    }
}
int mn[maxn][25];
void RMQ ( int n )
{
    for ( int i = 1; i <= n; i ++ )
        mn[i][0] = lcp[i];
    for ( int j = 1; ( 1 << j ) <= n; j ++ )
        for ( int i = 1; i+( 1 << ( j-1 ) ) <= n; i ++ )
            mn[i][j] = min ( mn[i][j-1], mn[ i+( 1 << ( j-1 ) ) ][j-1] );
}
int query ( int l, int r )
{
    int x = rk[l], y = rk[r];
    if ( x > y )
        swap ( x, y );
    x ++;
    int k = log2 ( y-x+1 ); //注意
    return min ( mn[x][k], mn[ y-( 1 << k )+1 ][k] );
}
void solve ( )
{
    int T, g, cas = 1;
    scanf ( "%d", &T );
    while ( T -- )
    {
        scanf ( "%d%s", &g, str );
        int len = strlen ( str );
        str[len] = 125;
        for ( int i = len-1; i >= 0; i -- )
            str[len+len-i] = str[i];
        str[len+len+1] = '\0';
        int n = 2*len+1;
        build_sa ( n+1, 200 );
        build_lcp ( n );
        RMQ ( n );
        LL ans = 0;
        for ( int L = 1; L < len/2; L ++ )
        {
            for ( int i = 0; i < len; i += L )
            {
                int j = i+L+g;
                if ( str[i] != str[j] )
                    continue ;
                int s = 0;
                if ( j < len )
                    s += min ( query ( i, j ), L );
                if ( i > 0 )
                    s += min ( query ( n-i, n-j ), L-1 );//往前最长为L-1
                ans += max ( 0, s-L+1 );
            }
        }
        printf ( "Case %d: %lld\n", cas ++, ans );
    }
}
int main ( )
{
    solve ( );
    return 0;
}
时间: 2024-10-03 23:02:26

UVA 10829 L-Gap Substrings的相关文章

uva 10829 - L-Gap Substrings(后缀数组)

题目链接:uva 10829 - L-Gap Substrings 题目大意:给定一个字符串,问有多少字符串满足UVU的形式,要求U非空,V的长度为g. 解题思路:对字符串的正序和逆序构建后缀数组,然后枚举U的长度l,每次以长度l分区间,在l和l+d+g所在的两个区间上确定U的最大长度. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using nam

UVa 1644 Prime Gap (水题,暴力)

题意:给定一个数 n,求它后一个素数和前一个素数差. 析:先打表,再二分查找. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <iostream> #include <cstring&

「kuangbin带你飞」专题十八 后缀数组

layout: post title: 「kuangbin带你飞」专题十八 后缀数组 author: "luowentaoaa" catalog: true tags: - kuangbin - 字符串 - 后缀数组 传送门 倍增法 struct DA{ bool cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l]; } int t1[maxn],t2[maxn],c[maxn]; int r

Linechart + Datagrid 互动展示数据 (Linechart自定义数据点选择线)

如上图示,在linechart中添加红色Y线,拖动该线的过程中,经过数据点时,会实时更新datagrid中对应的X.Y值数据. 实现要点: 1.linechart添加Y线 继承mx.charts.chartClasses.ChartElement,自定义Y线. package { import flash.display.Graphics; import flash.geom.Point; import flash.text.TextField; import mx.charts.chartCl

_DataStructure_C_Impl:SeqListBasedSort

// _DataStructure_C_Impl:Sort #include<stdio.h> #include<stdlib.h> #define MaxSize 50 typedef int KeyType; //数据元素类型定义 typedef struct{ KeyType key; //关键字 }DataType; //顺序表类型定义 typedef struct{ DataType data[MaxSize]; int length; }SqList; //------

8种基本的排序算法代码(不断更新)

最近看了两篇不错的博文,是介绍基本的查找和排序算法的,自己也在不断整理,先把代码放网上,参考资料如下: Victor Zhang SHIroh的专栏 以上资料中,一个没有代码,另一个使用的JAVA实现,我在这里使用C语言将它们实现了. 0 头文件声明 1 #include <stdio.h> 2 #include <stdlib.h> 3 typedef int Item; 4 #define key(A) (A) //返回关键字A 5 #define less(A, B) ( k

[ActionScript] AS3 绘制虚线

1 import flash.geom.Point; 2 import flash.display.MovieClip; 3 import flash.display.Graphics; 4 5 function drawDashed(mc:Sprite,p1:Point,p2:Point,length:Number=5,gap:Number=5):void 6 { 7 var max:Number = Point.distance(p1,p2); 8 var l:Number = 0; 9 v

冒泡、选择、插入、归并、希尔等排序算法的Python实现

一,冒泡排序 时间复杂度:O(n2) 稳定性:稳定 冒泡排序我就不多讲了,大体上就是比较相邻的两个数,每次把较大的数沉底.流程图大致上如下: 图是截得别人的,只是说明一下,代码没有参看别人的,写的不好,有更好的写法可以一起探讨.下面是代码: 1 def bubble(list): 2 #print(list) 3 for index in range(1,len(list)): #比较6趟 4 print(" index: %d" %index) 5 for index2 in ran

「luogu4135」作诗

「luogu4135」作诗 传送门 分块好题. 预处理出 \(f[i][j]\) 表示 \(i\) 号块到 \(j\) 号块的答案,\(num[i][k]\) 表示 \(k\) 在前 \(i\) 块的出现次数,暴力预处理,暴力查询,复杂度 \(O(n \sqrt n)\) 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) fr