codeforces 137D Palindromes (dp神题路基打印)
来源:互联网 发布:华为网络电话机 编辑:程序博客网 时间:2024/06/10 01:28
题意:
求一个串分成k个回文串需要的最少操作数,这个操作是指将串的某个位置的值改变以使得分成的串能够成为回文。
题解:
感觉神题啊,路径打印十分困难。
第一、我们要预处理下区间[i,j]上串变成回文的操作数!这步要用到区间dp来预处理,不断划分区间跟新。
第二、dp计算出最小的操作数,dp[i][j]表示前j个点分成i份回文串需要的最小操作数。
第三、获取,这就需要第二步中dp的值来倒推得到路径 通过这个判断:
if(dp[i][later]==dp[i-1][j]+cost[j+1][later]) 不断跟新later倒着推防止后效性!
路径的标记用mark[i]表示第i个切点的位置的后一个位置。
这还没完,有可能分割会出现相同的情况因此要盘重!! if(mark[i-1]!=mark[i]) mark[cnt++]=mark[i]
这些弄完后就可以开始修改字符串,用词要输出修改后的字符串,这步比较有技巧性,具体见代码!
第四、打印路径,路径就简单了,直接通过mark[i]标记的位置,然后在对应位置输出'+'
真心是神题!难点主要在第三部路径的获取处理,简直无解!
#include<iostream>#include<math.h>#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>#include<map>using namespace std;typedef long long lld;const int oo=0x3f3f3f3f;const lld OO=1LL<<61;const int MOD=1000000007;#define maxn 505int dp[maxn][maxn];int cost[maxn][maxn];int mark[maxn];char str[maxn];int n,k;void TheCnt(){ n=strlen(str+1); memset(cost,0,sizeof cost); for(int j=1;j<=n;j++) for(int i=1;i<=j;i++) cost[i][j]=cost[i+1][j-1]+(str[i]!=str[j]);}void Dp(){ memset(dp,0x3f,sizeof dp); dp[0][0]=0; for(int i=1;i<=k;i++) { for(int j=i;j<=n;j++) { for(int jj=i-1;jj<=j;jj++) if(dp[i-1][jj]!=oo) { dp[i][j]=min(dp[i-1][jj]+cost[jj+1][j],dp[i][j]); } } } printf("%d\n",dp[k][n]);}void output(){ int cnt; int later=n; for(int i=k;i>=1;i--) { for(int j=1;j<=n;j++) { if(dp[i-1][j]!=oo&&dp[i][later]==dp[i-1][j]+cost[j+1][later]) { mark[i]=j+1; later=j; break; } } } mark[k+1]=n+1; mark[1]=1; cnt=1;///防止有重复的切点///处理: for(int i=1;i<=k+1;i++) if(mark[i-1]!=mark[i]) mark[cnt++]=mark[i]; cnt-=2;//分成了cnt+1段 mark[cnt+1]=n+1;///修改字符串: for(int i=1;i<=cnt;i++) { int u=mark[i],v=mark[i+1]-1; while(u<v) { if(str[u]!=str[v]) str[v]=str[u]; u++; v--; } } cnt=2;//第一个的前面不用加+号所以直接跳过!! for(int i=1;i<=n;i++) { printf("%c",str[i]); if(i==mark[cnt]-1) { if(mark[cnt]!=n+1)printf("+"); cnt++; } } puts("");}int main(){ while(scanf("%s%d",str+1,&k)!=EOF) { TheCnt(); Dp(); output(); } return 0;}/**abacaba1abdcaba2abdcaba5abacababababbcbabcd3*/
0 0
- codeforces 137D Palindromes (dp神题路基打印)
- codeforces 41D Pawn (简单dp+路径打印)
- Codeforces 570E Pig and Palindromes dp
- Codeforces #316 E Pig and Palindromes DP
- codeforces #316 E. Pig and Palindromes (dp~)
- codeforces 159D dp + strings 好题
- 【DP】CodeForces 148D
- Codeforces 221D(dp)
- Codeforces 572D,DP
- codeforces 9D DP
- codeforces 519D dp
- Codeforces 358D【DP】
- codeforces 474D DP
- Codeforces 830D [DP]
- Codeforces Round #316 (Div. 2)E. Pig and Palindromes(dp好题)
- codeforces 245H Queries for Number of Palindromes 区间DP
- CodeForces 245H Queries for Number of Palindromes (区间DP)
- codeforces Queries for Number of Palindromes 区间dp
- django.for的使用
- POJ 3279 Fliptile
- (Android 入门)Android Matrix 的使用说明及工作原理
- Android学习笔记<四> ——回传值
- [推荐系统]Collaborative filtering 学习总结
- codeforces 137D Palindromes (dp神题路基打印)
- 分享android打开指定位置sqlite db的一个容错处理技巧
- 统计C#项目有效代码行数的实现过程
- c++/c 学习笔记--(4)
- Android开发中adb常用用法
- ViewPager动态添加、删除Fragment,且提供红色小圆球指示当前位置
- 人生思考
- [LeetCode]Pascal's Triangle II
- Web开发中最致命的8个小错误