18ICPC南京M 字符串

https://cn.vjudge.net/problem/2040809/origin

题意:在S串中找一个子串,在T串中找一个前缀,求拼起来是回文串的方案种数。

 

首先S串取出来的串可以分为s1 + s2,T串取出来的前缀为t,其中s1与t拼起来为回文串,s2本身为回文串

所以说对于s2,可以用马拉车预处理出S串中每个下标作为起点可以产生的回文串的数量。

对于s1可知s1的逆序与t相同,所以将S串翻转,用EXKMP求出每个后缀对t的LCP

最后两者贡献相乘就是答案。

 

赛后总结:

1.因为这题开在最大流和最小球覆盖后面,下意识认为应当是回文树或者后缀自动机才能做的字符串题,由于还没学到的原因产生了怯意

2.事实上开了一会儿之后发现并不是不可做,前一部分处理s2回文串的贡献在比赛的时候已经敲出来了,但是后一部分因为沉迷模拟样例aabbaa和aabb,S的逆序还是S,所以迷惑了做题的方法,下次应当自己搞一个比较普遍的样例、

3.总结起来 是字符串做的不够多

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <bitset>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x)
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
const double PI = acos(-1.0);
const double eps = 1e-9;
const int maxn = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int N,M,K;
char S[maxn],T[maxn];
char Ma[maxn << 1];
int Mp[maxn << 1];
LL pre[maxn << 1],val[maxn];
LL nxt[maxn],extend[maxn];
void Manacher(char s[],int len){
    int l = 0;
    Ma[l++] = '$';
    Ma[l++] = '#';
    for(int i = 0 ; i < len ; i ++){
        Ma[l++] = s[i];
        Ma[l++] = '#';
    }
    Ma[l] = 0;
    int mx = 0,id = 0;
    for(int i = 0; i < l ; i ++){
        Mp[i] = mx > i?min(Mp[2 * id - i],mx - i):1;
        while(Ma[i + Mp[i]] == Ma[i - Mp[i]]) Mp[i]++;
        if(i + Mp[i] > mx){
            mx = i + Mp[i];
            id = i;
        }
    }
}
void init(char* str,int l){
    Manacher(str,l);
    for(int i = 0 ; i < l * 2 + 2; i ++){
        //cout << i - (Mp[i] - 1) + 1 << endl;
        pre[i - (Mp[i] - 1) + 1]++;
        pre[i + 1]--;
    }
    int cnt = 0;
    for(int i = 1; i < l * 2 + 2; i ++){
        pre[i] += pre[i - 1];
        if(!(i & 1)){
            val[cnt++] = pre[i];
          //  cout << cnt - 1 << " " << val[cnt - 1] << endl;
        }
    }
   // cout << l << " " << cnt <<endl;
   // for(int i = 0 ; i < l; i ++){
   //     cout << val[i] << endl;
    //}
}
void pre_EKMP(char x[],int m,LL next[]){
    next[0] = m;
    LL j = 0;
    while(j + 1 < m &&x[j] == x[j + 1]) j ++;
    next[1] = j;
    LL k = 1;
    for(int i = 2; i < m ; i ++){
        LL p = next[k] + k - 1;
        LL L = next[i - k];
        if(i + L < p + 1) next[i] = L;
        else{
            j = max(0LL,p - i + 1);
            while(i + j < m && x[i + j] == x[j]) j ++;
            next[i] = j;
            k = i;
        }
    }
}
void EKMP(char x[],int m,char y[],int n,LL next[],LL extend[]){
    pre_EKMP(x,m,next);
    LL j = 0;
    while(j < n && j < m && x[j] == y[j]) j ++;
    extend[0] = j;
    LL k = 0;
    for(int i = 1; i < n ; i ++){
        LL p = extend[k] + k - 1;
        LL L = next[i - k];
        if(i + L < p + 1) extend[i] = L;
        else{
            j = max(0LL,p - i + 1);
            while(i + j < n &&j < m && y[i + j] == x[j]) j++;
            extend[i] = j;
            k = i;
        }
    }
}
int main(){
    //freopen("c.txt","r",stdin);
    scanf("%s%s",S,T);
    int l1 = strlen(S),l2 = strlen(T);
    //cout << l1 << " " << l2 <<endl;
    init(S,l1);
    reverse(S,S + l1); reverse(val,val + l1);
    EKMP(T,l2,S,l1,nxt,extend);
    LL ans = 0;
    for(int i = 1 ; i < l1; i ++){
       // if(extend[i] <100)cout << extend[i] << " " << val[i - 1] << endl;
        ans += 1ll * extend[i] * val[i - 1];
   // cout << ans <<endl;
    }
    Prl(ans);
    return 0;
}

 

posted @ 2019-08-05 14:42  Hugh_Locke  阅读(243)  评论(0编辑  收藏  举报