牛客练习赛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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮

浙公网安备 33010602011771号