返回顶部

牛客练习赛79 D.回文字D (DP,字符串hash)

  • 题意:RT,给你一个字符串,问你最少分割多少子串,满足这些子串均为D型回文串.

  • 题解:首先,判断回文我们可以用字符串hash来处理,这里不再赘述.

    我们设\(dp_i\),表示遍历到\(i\)位置时我们最少要分割多少子串来满足条件,我们看D型回文串的第一个条件,那么有:\(dp[i]=min(dp[i],min(dp[i-D+1],dp[i-D+2]...dp[i-1])+1)\).

    因为是动态区间最值问题,我们可以用一个单调队列来维护.

    那么我们还要用第二个条件,如果\(s_{i-D+1}...s_{i}\)是一个回文串,那么当前位置可以有:\(dp[i]=min(dp[i],dp[i-D]+1)\)转移过来,紧接着,如果\(s_{i-D+2}...s_{i+1}\)也是回文串,那么\(s_{i-D+1}...s_{i+1}\)就满足第二个条件,所以\(dp[i+1]\)既可以从\(dp[i-D+1]\)转移过来,也可以从\(dp[i-D+2]\)转移过来,那么对于这种连续回文串的情况,我们可以记一个前缀\(mi\)表示最优的状态,如果是回文就可以从\(mi\)转移过来,不是的话我们将\(mi\)设为\(INF\)即可.

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define ull unsigned long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e7 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
     ull base=23333;
     ull hash_l[N],hash_r[N];
     int q[N],hh=0,tt=-1;
     int dp[N];
     
    int main(){
        int n,d;
        string s;
        cin>>n>>d;
        cin>>s;
        if(d>n) {cout<<1<<'\n';return 0;}
        s=" "+s;
    
        ull b=1;
        rep(i,1,d) b=b*base;
    
        rep(i,1,n) hash_l[i]=hash_l[i-1]*base+s[i];
        per(i,n,1) hash_r[i]=hash_r[i+1]*base+s[i];
    
        int mi=INF;
        rep(i,1,n){
            dp[i]=INF;
            if(tt>=hh && i-q[hh]+1>d) hh++;
            if(i<d){
                dp[i]=1;
            }
            else{
                if(tt>=hh) dp[i]=min(dp[i],dp[q[hh]]+1);
                if(hash_l[i]-hash_l[i-d]*b==hash_r[i-d+1]-hash_r[i+1]*b) mi=min(mi,dp[i-d]);
                else mi=INF;
                dp[i]=min(dp[i],mi+1);
            }
            while(tt>=hh && dp[q[tt]]>=dp[i]) tt--;
            q[++tt]=i;
        }
    
        cout<<dp[n]<<'\n';
     
    return 0;
    }
    
posted @ 2021-03-29 10:34  _Kolibri  阅读(66)  评论(0)    收藏  举报