题意:

演队在口试中非常不幸。在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 }

URAL - 1635 哈希区间(或者不哈希)+dp的更多相关文章

  1. URAL 1635 Mnemonics and Palindromes

    URAL 1635 思路:区间dp+贪心,先n^2处理出每段区间是否是回文串,然后贪心地找每一段1到i的最少分割. 代码: #include<bits/stdc++.h> using na ...

  2. 回文串+回溯法 URAL 1635 Mnemonics and Palindromes

    题目传送门 /* 题意:给出一个长为n的仅由小写英文字母组成的字符串,求它的回文串划分的元素的最小个数,并按顺序输出此划分方案 回文串+回溯:dp[i] 表示前i+1个字符(从0开始)最少需要划分的数 ...

  3. Ural 1635 Mnemonics and Palindromes(DP)

    题目地址:space=1&num=1635">Ural 1635 又是输出路径的DP...连着做了好多个了. . 状态转移还是挺简单的.要先预处理出来全部的回文串,tag[i] ...

  4. Codeforces 811C Vladik and Memorable Trip (区间异或最大值) (线性DP)

    <题目链接> 题目大意: 给你n个数,现在让你选一些区间出来,对于每个区间中的每一种数,全部都只能出现在这个区间. 每个区间的价值为该区间不同的数的异或值之和,现在问你这n个数最大的价值是 ...

  5. Java集合(九)哈希冲突及解决哈希冲突的4种方式

    Java集合(九)哈希冲突及解决哈希冲突的4种方式 一.哈希冲突 (一).产生的原因 哈希是通过对数据进行再压缩,提高效率的一种解决方法.但由于通过哈希函数产生的哈希值是有限的,而数据可能比较多,导致 ...

  6. URAL 1635. Mnemonics and Palindromes(DP)

    题目链接 本来用区间DP,3次方的复杂度,T了,看了看题解,降维,直接二次方的复杂度可以解.然后折腾一下输出路径..终于过了. #include <cstring> #include &l ...

  7. Ural 1183 Brackets Sequence(区间DP+记忆化搜索)

    题目地址:Ural 1183 最终把这题给A了.. .拖拉了好长时间,.. 自己想还是想不出来,正好紫书上有这题. d[i][j]为输入序列从下标i到下标j最少须要加多少括号才干成为合法序列.0< ...

  8. Memcached 笔记与总结(5)Memcached 的普通哈希分布和一致性哈希分布

    普通 Hash 分布算法的 PHP 实现 首先假设有 2 台服务器:127.0.0.1:11211 和 192.168.186.129:11211 当存储的 key 经过对 2 (2 台服务器)取模运 ...

  9. 算法初级面试题05——哈希函数/表、生成多个哈希函数、哈希扩容、利用哈希分流找出大文件的重复内容、设计RandomPool结构、布隆过滤器、一致性哈希、并查集、岛问题

    今天主要讨论:哈希函数.哈希表.布隆过滤器.一致性哈希.并查集的介绍和应用. 题目一 认识哈希函数和哈希表 1.输入无限大 2.输出有限的S集合 3.输入什么就输出什么 4.会发生哈希碰撞 5.会均匀 ...

随机推荐

  1. GC算法介绍及工作原理和优缺点

    一.GC定义与作用 GC就是垃圾回收机制的简写 GC可以找到内存中的垃圾,并释放和回收空间,GC里的垃圾是什么 如下图所示: GC算法是什么:GC是一种机制,垃圾回收器完成具体的工作 工作的内容就是查 ...

  2. (十一)time模块

    三种时间表示 在Python中,通常有这几种方式来表示时间: 时间戳(timestamp) :通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量.我们运行"ty ...

  3. 计算起始车站车费问题-JavaScript数组对象写法

    计算起始站车费 题目:深圳--60--广州--50-虎门--40- -中山--36-珠海一34-澳门一89一香港以上车票费用计算,如坐车深圳到广州60元,广州到虎门50元,深圳到虎门就是60+50-1 ...

  4. 【Linux】E297: Write error in swap file 解决办法

    今天登陆到服务器上,发现通过vi 打开文件就会报错: E297: Write error in swap file E303: Unable to open swap file for "c ...

  5. 【Oracle】创建用户配额总是不足的解决问题 quota

    在oracle中,正常创建的用户是没有配额限制的,也就是默认的是unlimited on tablespace的,但是在有些时候,没有设置相关的配额,用户总是会报错用户配额严重不足,查看表空间,也有很 ...

  6. MySQL全面瓦解17:触发器相关

    关于触发器 现实开发中我们经常会遇到这种情况,比如添加.删除和修改信息的时候需要记录日志,我们就要在完成常规的数据库逻辑操作之后再去写入日志表,这样变成了两步操作,更复杂了. 又比如删除一个人员信息的 ...

  7. XEE - Pikachu

    概述 XXE -"xml external entity injection"既"xml外部实体注入漏洞".概括一下就是"攻击者通过向服务器注入指定的 ...

  8. 解决maven中某些依赖无法下载,手动安装Maven依赖

    <!--先下载jar包,然后在仓库中手动安装,下面是遇到的两个例子--> <!--第一个--> mvn install:install-file -Dfile=D:\kaptc ...

  9. 从synchronized和lock区别入手聊聊java锁机制

    写这篇文章之前,我去百度了一下啥叫锁,百度百科上写道:置于可启闭的器物上,以钥匙或暗码开启.确实我们一般理解的锁就是门锁,密码锁,但是在计算机科学中,锁又是啥,说实话,这个问题我也思考了很久,也没法很 ...

  10. OpenStack各组件的常用命令

    openstack命令 openstack-service restart    #重启openstack服务 openstack endpoint-list        #查看openstack的 ...