华工校赛 K- Parco_Love_String

题目链接

题意

给定一个长度为 n ( 1 n 1 0 3 ) n(1 \leq n \leq 10^3) n(1n103)的字符串 s s s,给 T ( 1 T 1 0 5 ) T(1\leq T \leq 10^5) T(1T105)次询问,

每次询问一个 x x x,要求输出 s [ 1.. x ] s[1..x] s[1..x] s [ x + 1... n ] s[x+1...n] s[x+1...n]的公共子串的对数.

做法

由于字符串的长度较小,可以先预处理出所有的答案,然后 O ( 1 ) O(1) O(1)输出.

考虑 a n s [ i ] ans[i] ans[i] a n s [ i + 1 ] ans[i+1] ans[i+1]的转移: a n s [ i + 1 ] = a n s [ i ] n u m ( s u f i + 1 s [ 1.. i ] ) + n u m ( p r e i + 1 s [ i + 1.. n ] ) ans[i+1]=ans[i] - num(suf_{i+1}在s[1..i]中的前缀匹配之和)+num(pre_{i+1}在s[i+1..n]的后缀匹配之和) ans[i+1]=ans[i]num(sufi+1s[1..i])+num(prei+1s[i+1..n])

队友在比赛中用后缀自动机 ( O ( n 2 ) ) (O(n^2)) (O(n2))搞过去了,后来看牛逼网友的代码,这东西可以 d p dp dp解决.(其实这玩意就是个lcp)

d p [ i ] [ j ] [ 0 ] i j dp[i][j][0]表示以i开始的子串与以j开始的子串的最长匹配长度 dp[i][j][0]ij

d p [ i ] [ j ] [ 1 ] i j dp[i][j][1]表示以i结束的子串与以j结束的子串的最长匹配长度 dp[i][j][1]ij.

则有 a n s [ i + 1 ] = a n s [ i ] j = 1 i m i n ( d p [ i + 1 ] [ j ] [ 0 ] , i + 1 j ) + j = i + 1 n m i n ( d p [ i + 1 ] [ j ] [ 1 ] , j i ) . ans[i+1]=ans[i]-\sum_{j=1}^i min(dp[i+1][j][0],i+1-j)+\sum_{j=i+1}^n min(dp[i+1][j][1],j-i). ans[i+1]=ans[i]j=1imin(dp[i+1][j][0],i+1j)+j=i+1nmin(dp[i+1][j][1],ji).

复杂度 O ( n 2 ) O(n^2) O(n2)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 7;
int dp[N][N];
char s[N];
ll ans[N];

int main() {
#ifdef local
    freopen("in.txt", "r", stdin);
#endif
    scanf("%s", s + 1);
    int n = strlen(s + 1);
    for(int i = 1; i <= n; i++)
        for(int j = i + 1; j <= n; j++)
            if(s[i] == s[j]) dp[i][j] = dp[i-1][j-1]+1;
    for(int i = n; i; i--)
        for(int j = i-1; j; j--)
            if(s[i] == s[j]) dp[i][j] = dp[i+1][j+1]+1;
    ll now = 0;
    for(int i = 2; i <= n; i++)
        if(s[i] == s[1]) now++;
    ans[1] = now;
    for(int i = 2; i <= n; i++) {
        for(int j = i - 1; j; j--) now -= min(i - j, dp[i][j]);
        for(int j = i + 1; j <= n; j++) now += min(j - i, dp[i][j]);
        ans[i] = now;
    }
    int q; scanf("%d", &q);
    for(int i = 0, x; i < q; i++)
        scanf("%d", &x), printf("%lld\n", ans[x]);
    return 0;
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务