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 }

 

    以下这个是我的,写得比较痛苦,没有做出来,纪念下(读者请忽略)

    

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

 

posted @ 2014-11-13 22:50  windysai  阅读(306)  评论(0编辑  收藏  举报