URAL - 1635 哈希区间(或者不哈希)+dp
题意:
演队在口试中非常不幸。在42道考题中,他恰好没有准备最后一道题,而刚好被问到的正是那道题。演队坐在教授面前,一句话也说不出来。但教授心情很好,给了演队最后一次通过考试的机会。他让这个可怜的学生说出考试要考的科目。不幸的是,演队想不起这个科目名字,尽管他记得科目里有诸如安全、程序、设备、可能还有信息学……
为了准备复试,演队决定记住这门课的名字。为了更好地记住那根长字符串,他决定把它分解成回文,并分别学习每个回文。当然,分解过程中的回文数必须尽可能少。
Input
输入一行字符串表示为这门课的名字。这是由小写英文字母组成的非空行。这一行的长度最多是4000个字符。
Output
第一行输出可以分解科目名称的最小的回文字符串数目。在第二行输出回文所有的回文字符串,由空格分隔。如果有几个答案是可能的,输出其中任何一个。
Input
pasoib
Output
6
p a s o i b
Input
zzzqxx
Output
3
zzz q xx
Input
wasitacatisaw
Output
1
wasitacatisaw
题解:
可以对每一个区间[l,r]用哈希赋一个唯一的值,对区间[l,r]正序哈希一个值,逆序哈希一个值。那么如果区间[l,r]是回文串,那么这个区间的正序哈希值应该等于逆序哈希值
dp[i]=min(dp[j-1]+1,dp[i])
,dp[i]代表从1-i
区间的回文序列数量
这个状态转移方程就是当区间[j,i]是回文串的时候
如果不会哈希,也可以用一个二维数组来记录一下区间[l,r]是不是回文串,判断回文串就用while循环(这种方法见代码2)
代码1:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #include<vector> 7 #include<map> 8 #define mem(a,x) memset(a,x,sizeof(a)) 9 using namespace std; 10 const int INF=0x3f3f3f3f; 11 const int maxn=4005; 12 const int mod=1000000009; 13 const int base=13333; 14 typedef long long ll; 15 ll dp[maxn];//从1--i中回文串的最少个数 16 ll h1[maxn],h2[maxn],p[maxn],n; 17 ll pre[maxn]; 18 char s[maxn]; 19 string str[maxn]; 20 //找出来[l,r]这个区间正序的哈希值 21 ll get1(ll l,ll r) 22 { 23 return h1[r]-h1[l-1]*p[r-l+1]; 24 } 25 //找出来[l,r]这个区间倒序的哈希值 26 ll get2(ll l,ll r) 27 { 28 return h2[r]-h2[l-1]*p[r-l+1]; 29 } 30 //如果区间[l,r]的正序逆序哈希值一样,那么这个区间就是回文串 31 bool check(ll i,ll j) 32 { 33 if(get1(i,j)==get2(n-j+1,n-i+1)) 34 return true; 35 return false; 36 } 37 int main() 38 { 39 ios::sync_with_stdio(false); 40 cin.tie(0); 41 memset(dp,INF,sizeof dp); 42 dp[0]=0; 43 cin>>(s+1); 44 n=strlen(s+1); 45 p[0]=1; 46 for(ll i=1; i<=n; i++) 47 { 48 h1[i]=h1[i-1]*base-s[i]-'a'+1; 49 h2[i]=h2[i-1]*base-s[n+1-i]-'a'+1; 50 p[i]=p[i-1]*base; 51 } 52 for(ll i=1; i<=n; i++) 53 { 54 for(ll j=1; j<=i; j++) 55 { 56 if(check(j,i)) 57 { 58 if(dp[i]>(dp[j-1]+1)) 59 { 60 pre[i]=j; //记录路径 61 dp[i]=dp[j-1]+1; 62 } 63 } 64 } 65 } 66 cout<<dp[n]<<endl; 67 int id=0; 68 int now=n; 69 while(now) 70 { 71 for(int i=pre[now]; i<=now; i++) 72 str[id]+=s[i]; //str串记录回文串 73 now=pre[now]-1; 74 id++; 75 } 76 for(int i=id-1; i>=0; i--) 77 { 78 if(i!=0) 79 cout<<str[i]<<' '; 80 else 81 cout<<str[i]<<endl; 82 } 83 }
代码2:(参考:https://blog.csdn.net/zmx354/article/details/20078995)
1 #include <iostream> 2 3 #include <algorithm> 4 5 #include <cstdlib> 6 7 #include <cstdio> 8 9 #include <cstring> 10 11 #include <queue> 12 13 #include <cmath> 14 15 #include <stack> 16 17 18 19 #pragma comment(linker, "/STACK:1024000000"); 20 21 #define LL long long int 22 23 #define ULL unsigned long long int 24 25 #define _LL __int64 26 27 #define INF 0x3f3f3f3f 28 29 #define Mod 1000000009 30 31 32 33 using namespace std; 34 35 36 37 char s[4010]; 38 39 40 41 bool dp[4001][4001]; 42 43 44 45 int ans[4010]; 46 47 48 49 int di[4010]; 50 51 52 53 void Output(int l) 54 55 { 56 57 if(l == 0) 58 59 return ; 60 61 62 63 Output(di[l]); 64 65 66 67 if(di[l] != 0) 68 69 printf(" "); 70 71 72 73 for(int i = di[l]+1;i <= l; ++i) 74 75 { 76 77 printf("%c",s[i]); 78 79 } 80 81 } 82 83 84 85 int main() 86 87 { 88 89 int l,i,j,h,e; 90 91 92 93 scanf("%s",s+1); 94 95 96 97 l = strlen(s+1); 98 99 100 101 memset(dp,false,sizeof(dp)); 102 103 104 105 for(i = 1;i <= l; ++i) 106 107 { 108 109 dp[i][i] = true; 110 111 h = i-1; 112 113 e = i+1; 114 115 116 117 while(1 <= h && e <= l && s[h] == s[e]) 118 119 { 120 121 dp[h][e] = true; 122 123 h--,e++; 124 125 } 126 127 128 129 h = i,e = i+1; 130 131 132 133 while(1 <= h && e <= l && s[h] == s[e]) 134 135 { 136 137 dp[h][e] = true; 138 139 h--,e++; 140 141 } 142 143 } 144 145 146 147 memset(ans,INF,sizeof(ans)); 148 149 150 151 ans[0] = 0; 152 153 154 155 di[1] = 0; 156 157 158 159 for(i = 1;i <= l; ++i) 160 161 { 162 163 for(j = i;j >= 1; --j) 164 165 { 166 167 if(dp[j][i]) 168 169 { 170 171 if(ans[i] > ans[j-1]+1) 172 173 { 174 175 ans[i] = ans[j-1]+1; 176 177 di[i] = j-1; 178 179 } 180 181 } 182 183 } 184 185 } 186 187 188 189 printf("%d\n",ans[l]); 190 191 192 193 Output(l); 194 195 196 197 puts(""); 198 199 200 201 return 0; 202 203 }