hihocoder #1799 : 基因合成(最长回文子串+暴力剪枝)

题目链接

#1799 : 基因合成

分析

可以递归的想,如果有回文,那么肯定是做2操作划算一些,记 R [ i ] manacher 算法中以 i 为中心的回文串半径,注意这里只能是偶数长度的回文串。具体来说 str[l,r] 的操作代价为

c o s t ( l , r ) = m i n i = 1 n { r l + 1 + 1 + c o s t ( i , i + R [ i ] / 2 1 ) }

注意由于是回文串,递归计算最多有 l o g N 次,因此暴力剪枝丫就算就好,

code

#include <bits/stdc++.h>
using namespace std;

#define MAXN (200100)
#define MOD 1000000007
#define ms(x,v) memset((x),(v),sizeof((x)))
#define INF 0x3f3f3f3f
#define pb push_back
#define fi first
#define se second
#define mp make_pair

typedef unsigned long long uLL;
typedef long long LL;
typedef pair<int,int > Pair;

/*****  field ****/

char str[MAXN],pp[MAXN*2];
int R[MAXN*2]; // 回文串半径
int n,len;
int ans =0;
/********function *********/

void manacher(){
    // preprocess
    n = strlen(str+1);
    len=1;
    char pad = '#';
    pp[0] = '$';
    for(int i=1 ; i <= n ; ++i){
        pp[len++] = pad;
        pp[len++] = str[i];
    }
    pp[len++] = pad;
    ms(R,0);
    int mr=0,zx =0;//mr 刚好越过最右回文的点
    for(int i=1 ; i<len ; ++i){
        R[i] = mr > i? min(R[2*zx -i],mr -i) : 1;
        while (pp[i+R[i]]==pp[i-R[i]])++R[i];
        if(i+R[i]> mr){
            mr = i+R[i];
            zx = i;
        }
    }
}

int solve(int l,int r){

    if(r<l)return 0;
    if(r-l <=1)return r-l+1;
    int sz = r-l+1;
    int ret = sz;

    for(int i=(l<<1)+1 ; i <=(r<<1) ; i+=2){
        int rad = min(R[i],min(i-(l<<1)+2,2*r+2 - i)) -1;
        if(sz - rad+1 >=ret)continue;
        int ll = (i+1)>>1;
        int rr = (i+rad)>>1;
        int remain = sz - rad+1 + solve(ll,rr);
        ret = min(ret,remain);
    }
    return ret;
}

int main(int argc, char const *argv[]) {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin>>T;
    while (T--) {
        cin >> (str+1);
        manacher();
        // for(int i=1 ; i<=len ; ++i)std::cout << R[i] << ' ';std::cout  << '\n';
        std::cout << solve(1,n) << '\n';
    }


    return 0;
}

猜你喜欢

转载自blog.csdn.net/Dylan_Frank/article/details/81437256