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 }
View Code

 

代码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 }
View Code

 

posted @ 2020-04-07 15:38  kongbursi  阅读(312)  评论(0编辑  收藏  举报