Back to text D (hash+dp+monotonic queue)

https://ac.nowcoder.com/acm/contest/11169/D


Ideas:

Author: hx073269
link: https://ac.nowcoder.com/discuss/625099?type=101&channel=-1&source_id=0
Source: Cattle customer network

test sites: dynamic programming + string hash
set DP [i] for the first i letters The composed string is at least divided into DP[i] segments, then the final answer is DP[n], and the transfer can be divided into the following two types:
①Because the strings of length less than D are all D-type palindrome strings, so there is DP[ i]=min(DP[i],min(DP[i-1],DP[i-2],...,DP[i-D+1])+1). Here, a monotonic queue can be used to maintain the minimum value of the fixed-length interval.
② Define a position i as "good" if and only if [i-D+1,i] is a palindrome. If the interval [i-D+1,i] is a palindrome string, then let mi=min(mi,DP[iD]); if not, let mi=INF. Because the "good" positions are continuous, we directly let mi update as i increases, and at the same time let DP[i]=min(DP[i],mi+1) every time. Here you can use the string hash preprocessing to quickly determine the palindrome string.
The above idea is relatively natural. In fact, it can be found that the DP array is monotonous and undecreasing, so only the smallest l is required, so that [l,i] is a D-type palindrome string, then let DP[i]=DP[l- 1] +1 is fine. Therefore, we can complete the transfer without using a monotonic queue.
Time complexity: O(n).


#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e7+100;
typedef long long LL;
const LL base=131;
const LL mod=998244353;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL h[maxn],p1[maxn],p2[maxn];
char str[maxn];
LL dp[maxn];
LL Q[maxn],t=0,f=0;///t--队头,f---队尾
LL check(LL p[],LL l,LL r){
    return (p[r]%mod-p[l-1]*h[r-l+1]%mod+mod)%mod;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n,D;cin>>n>>D;
  cin>>(str+1);
  if(D>n){
    cout<<"1"<<"\n";return 0;
  }
  h[0]=1;
  LL mi=1e9;
  for(int i=1;i<maxn;i++) h[i]=h[i-1]*base%mod;
  for(int i=1;i<=n;i++) p1[i]=(p1[i-1]*base%mod+(str[i]-'a'+1))%mod,p2[i]=(p2[i-1]*base%mod+(str[n-i+1]-'a'+1))%mod;
  for(int i=1;i<=n;i++){
    dp[i]=1e9;
    if(i<D){
        dp[i]=1;
    }
    else{
        if(t>f) dp[i]=min(dp[i],dp[Q[f]]+1);
        if(check(p1,i-D+1,i)==check(p2,n-i+1,n-i+D)) mi=min(mi,dp[i-D]);
        else mi=1e9;
        dp[i]=min(dp[i],mi+1);
    }
    while(t>f&&dp[Q[t-1]]>=dp[i]) t--;
    Q[t++]=i;
    while(t>f&&i-Q[f]+1>=D) f++;
  }
  cout<<dp[n]<<"\n";
return 0;
}

 

Guess you like

Origin blog.csdn.net/zstuyyyyccccbbbb/article/details/115263472