codeforces 486C. Palindrome Transformation 解题报告
题目链接:http://codeforces.com/problemset/problem/486/C
题目意思:给出一个含有 n 个小写字母的字符串 s 和指针初始化的位置(指向s的某个字符)。可以对s进行四种操作:up,down,left,right。up/down是令到对称位置的字符相同所进行的操作次数。假设s[i] != s[j](i, j是对称的,假设分别是a, k),up: a(位置1) 根据字母表顺序变成 k(位置11) 需要 10 次(直接a->k)。down:a 根据 字母表逆向顺序变成 k 需要 16 次(a->z->k)。 left/right 主要是操作移动的指针。假如当前指向pos,left: i: 1~pos-1 中 找到s[i] != s[n-i+1], right: j: pos+1 ~ n 找到 s[j] != s[n-j+1]。
问使得s最终成为回文串需要使用这四种操作的最少次数是多少。
如果按题目要求直接一步一步模拟做,会发现好复杂。做了我两个多小时,无果!不仅指针会随时变动,而且当指向第一个元素的时候,又可以移动到最后一个元素(可以循环),还要比较左右两边的距离再判断移动的方向.......
看了题解,真是太厉害了。其实没有必要考虑这么多,前提是要知道需要变动的位置,这个不难。进行 up/down 操作。然后以 p 为中点向左右两边探测,选择离 p 较近的位置的方向,代表这个方向要走两次,另外那个自然就是一次了。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 8 const int maxn = 1e5 + 5; 9 bool ok[maxn]; 10 11 string s; 12 13 int main() 14 { 15 #ifndef ONLINE_JUDGE 16 freopen("in.txt", "r", stdin); 17 #endif 18 19 int n, p; 20 while (scanf("%d%d", &n, &p) != EOF) 21 { 22 cin >> s; 23 s = "Y" + s; // 下标往右移了一位,刚好对应题目给出的下标 24 memset(ok, false, sizeof(ok)); 25 int ans = 0; 26 for (int i = 1; i <= n/2; i++) 27 { 28 if (s[i] != s[n-i+1]) // 要变动的位置 29 { 30 if (abs(p-i) > abs(p-(n-i+1))) // p位置离哪边近 31 ok[n-i+1] = true; 32 else 33 ok[i] = true; 34 int tmp = abs(s[i]-s[n-i+1]); 35 ans += min(26-tmp, tmp); // 求down/up 操作次数 36 } 37 } 38 // 找出指针移动的最大距离 39 int l = p, r = p; 40 for (int i = 1; i <= p; i++) 41 { 42 if (ok[i]) 43 { 44 l = i; 45 break; 46 } 47 } 48 for (int i = n; i >= p; i--) 49 { 50 if (ok[i]) 51 { 52 r = i; 53 break; 54 } 55 } 56 // 求left/right 操作次数 57 ans += abs(p-l) + abs(p-r); 58 ans += min(abs(p-l), abs(p-r)); // 距离短的那边要走两次: lrr, rll(以p为界) 59 printf("%d\n", ans); 60 } 61 return 0; 62 }
以下这个是我的,写得比较痛苦,没有做出来,纪念下(读者请忽略)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 1e5 + 5; 9 char s[maxn]; 10 int n, p, ans; 11 12 inline int change_num(int cur) 13 { 14 int x = s[cur] - 'a'; 15 int y = s[n-cur-1] - 'a'; 16 int change1 = y - x; 17 int change2 = x + 26 - y; 18 s[cur] = s[n-cur-1]; 19 return min(change1, change2); 20 } 21 22 inline int get_moves(int cur) // 这里存在大问题,比较难修改 23 { 24 printf("cur = %d\n", cur); 25 int l = cur - 1, r = cur + 1; 26 l = (l < 0 ? n - 1 : l); 27 r = (r >= n ? 0 : r); 28 int cntl = 1; 29 int cntr = 1; 30 printf("before: l = %d, cntl = %d\n", l, cntl); 31 printf(" r = %d, cntr = %d\n", r, cntr); 32 33 while (s[l] == s[n-l-1] && l != cur && l != n-l-1) 34 { 35 cntl++; 36 l = (l < 0 ? n - 1 : l-1); 37 } 38 39 while (s[r] == s[n-r-1] && r != cur && r != n-r-1) 40 { 41 cntr++; 42 r = (r >= n ? 0 : r); 43 printf("in: r = %d\n", r); 44 } 45 46 printf("after: l = %d, cntl = %d\n", l, cntl); 47 printf(" r = %d, cntr = %d\n", r, cntr); 48 if (cntl < cntr) 49 return -cntl; 50 return cntr; 51 } 52 53 int main() 54 { 55 #ifndef ONLINE_JUDGE 56 freopen("in.txt", "r", stdin); 57 #endif 58 59 while (scanf("%d%d", &n, &p) != EOF) 60 { 61 scanf("%s", s); 62 int cnt = 0; 63 for (int i = 0; i < n/2; i++) 64 { 65 if (s[i] != s[n-i-1]) 66 cnt++; 67 } 68 int ans = 0; 69 p--; 70 if (s[p] != s[n-p-1]) 71 { 72 ans += change_num(p); 73 cnt--; 74 } 75 // printf("cnt = %d\n", cnt); 76 // printf("before: ans = %d\n", ans); 77 int after, now = p; 78 while (cnt) 79 { 80 int after = get_moves(now); 81 printf("after = %d\n", after); 82 now += after; 83 ans += abs(after); 84 ans += change_num(now); 85 printf("s = %s\n", s); 86 printf("ans = %d\n\n", ans); 87 cnt--; 88 if (now == p) 89 break; 90 } 91 printf("%d\n", ans); 92 } 93 return 0; 94 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步