zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", 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
    ", l, cntl);
    31     printf("        r = %d, cntr = %d
    ", 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
    ", r);
    44     }
    45 
    46     printf("after:  l = %d, cntl = %d
    ", l, cntl);
    47     printf("        r = %d, cntr = %d
    ", 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
    ", cnt);
    76     //    printf("before:  ans = %d
    ", ans);
    77         int after, now = p;
    78         while (cnt)
    79         {
    80             int after = get_moves(now);
    81             printf("after = %d
    ", after);
    82             now += after;
    83             ans += abs(after);
    84             ans += change_num(now);
    85             printf("s = %s
    ", s);
    86             printf("ans = %d
    
    ", ans);
    87             cnt--;
    88             if (now == p)
    89                 break;
    90         }
    91         printf("%d
    ", ans);
    92     }
    93     return 0;
    94 }
    View Code
  • 相关阅读:
    时装画基础知识--如何画人体
    马士兵java视频学习顺序
    Mysql 中文字符乱码问题
    zendstudio 设置默认编码 utf-8 gbk
    MYSQL 本地无ROOT权限 忘记密码
    windows 3389 远程
    windows 老掉牙CMD的命令
    mysql-常用注入渗透手法
    ubuntu 添加多个IP
    windows下简单配置apache
  • 原文地址:https://www.cnblogs.com/windysai/p/4096116.html
Copyright © 2011-2022 走看看