Problem
有一个字符串S,求S最少可以被划分为多少个回文串。 例如:abbaabaa,有多种划分方式。
a|bb|aabaa - 3 个回文串 a|bb|a|aba|a - 5 个回文串 a|b|b|a|a|b|a|a - 8 个回文串
其中第1种划分方式的划分数量最少。
Solution
先预处理,然后见官方攻略:
𝑑𝑝[𝑖]表示以𝑖结尾的划分数量的最小值,𝑑𝑝[𝑖]=𝑚𝑖𝑛(𝑑𝑝[𝑖],𝑑𝑝[𝑗]+1) 当𝑗<𝑖且从𝑗到𝑖是一个回文串时。所以对于字符𝑆,逐个处理𝑆的字符,枚举以𝑆𝑖为中心的所有回文串,做状态转移即可。复杂度𝑂(𝑛2)。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| #include<stdio.h> #include<set> #include<iostream> #include<stack> #include<cstring> #include<cmath> #include<vector> #include<map> #include<queue> #include<algorithm> typedef long long ll; typedef long double ld; typedef double db; #define io_opt ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) using namespace std; const int mod=1e9+7; inline int mo(ll a,int p){ return a>=p?a%p:a; } inline int rd() { int x = 0, f = 1; char ch; while (ch < '0' || ch > '9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return f * x; } inline ll gcd(ll x, ll y){ return y==0?x:gcd(y,x%y); } inline ll speed(ll a,ll b,int p){ ll cur=a,anss=1; while(b){ if(b&1) anss=anss*cur%p; cur=cur*cur%p; b>>=1; } return anss%p; } const int MAXN=1e5; bool ipr[MAXN+20];
int len; char s[5020]; int dp[5020][5020]; int dp2[5020]; vector<int>vec; int main(){ scanf("%s",s); len=strlen(s); for(int i=len-1;i>=0;i--){ dp[i][i]=1; for(int j=i+1;j<len;j++){ if(s[i]==s[j]){ if(i+1>=j-1) dp[i][j]=1; else dp[i][j]=dp[i+1][j-1]; } } } for(int i=0;i<len;i++){ dp2[i]=dp[0][i]?1:i+1; if(dp2[i]>1) for(int j=0;j<i;j++){ if(dp[j+1][i]&&dp2[j]+1<dp2[i]) dp2[i]=dp2[j]+1; } } printf("%d\n",dp2[len-1]); return 0; }
|