【Codeforces 486C】Palindrome Transformation

【链接】 我是链接,点我呀:)
【题意】


光标一开始在p的位置
你可以用上下左右四个键位移动光标(左右)或者更改光标所在的字符(上下增加或减少ascill码)
问你最少要操作多少次才能使得字符串变成回文

【题解】


首先把字符串分成两个部分
1..n/2 和 n/2+1..n这两个部分 (如果n是奇数比较特殊,右半部分是n/2+2..n)
然后如果p落在右半部分那个区间的话
就让它做一下对称
到左半部分来
因为不可能从右边那个区间移动到左边那个区间的(跨越n到达1),那样做太不划算
这两个区间其实是等价的,因为转换的代价都是相同的
只需让光标在一个区间里面移动就好
然后我们就只要考虑一个区间了(1..n/2),
先算出来每个位置转换成回文串对应的位置的字符需要的代价cost[i]
然后求一个前缀和(我直接在cost[i]上求的前缀和,直接导致我忘记cost[i]代表的是cost[1..i]。。。。)
然后再把这一个区间分成(1..p-1)和(p+1,n/2)
我们用前缀和求出cost[1..p-1]和cost[p+1,n/2]
这一部分答案是肯定要累加的。
然后我们只要知道我们往左和往右走最近需要走到哪里(因为不一定非得走到1或者走到n/2)
记往左走最少需要走的步数为leftstep,同理向右为rightstep
(如果不用往左走或不用往右走那么对于的xxxstep=0)
那边要的步数少,我们就先走到那边
因为这样的话,回到p位置所需要的花费比较少
则答案累加min(leftstep,rightstep)*2+max(leftstep,rightstep)
这样就做完了!

【代码】

import java.io.*;
import java.util.*;

public class Main {
    
    
    static InputReader in;
    static PrintWriter out;
        
    public static void main(String[] args) throws IOException{
        //InputStream ins = new FileInputStream("E:\\rush.txt");
        InputStream ins = System.in;
        in = new InputReader(ins);
        out = new PrintWriter(System.out);
        //code start from here
        new Task().solve(in, out);
        out.close();
    }
    
    static int N = 50000;
    static class Task{
        
        final int N = (int)1e5; 
        String s;
        int n,p;
        int cost[];
        
        int get_sum(int l,int r) {
            if (l>r) return 0;
            return cost[r]-cost[l-1];
        }
        
        public void solve(InputReader in,PrintWriter out) {
            cost = new int[N+10];
            n = in.nextInt();p = in.nextInt();
            s = in.next();
            StringBuilder sb = new StringBuilder(s);
            sb.insert(0, ' ');
            s = sb.toString();
            int half = n/2;
            for (int i = 1;i <= half;i++) {
                int j = n-i+1;
                int x = s.charAt(i)-'a'+1;
                int y = s.charAt(j)-'a'+1;
                int temp1 = Math.abs(x-y);
                int temp2 = 26-Math.max(x, y) + Math.min(x, y) - 1 + 1;
                cost[i] = Math.min(temp1, temp2);
            }
            for (int i = 1;i <= half;i++) cost[i]+=cost[i-1];
            
            if (cost[half]==0) {
                out.println(0);
                return;
            }
            int ans = 0;
            if (n%2==1 && p==half+1) {
                ans++;
                p--;
            }
            if (p>half) {
                int delta;
                if (n%2==1) {
                    delta = p-(half+1);
                    p = half+1-delta;
                }else {
                    delta = p-half;
                    p = half-delta+1;
                }
            }
            ans = ans + get_sum(p,p);
            int leftcost = get_sum(1,p-1);
            int rightcost = get_sum(p+1,half);
            ans = ans + leftcost + rightcost;
            int leftstep = 0,rightstep = 0;
            int temp = 0;
            for (int i = p-1;i >= 1;i--) {
                if (temp==leftcost) break;
                leftstep++;
                temp+=get_sum(i,i);
            }
            temp = 0;
            for (int i = p+1;i <= half;i++) {
                if (temp==rightcost) break;
                rightstep++;
                temp+=get_sum(i,i);
            }
            //out.println("leftstep="+leftstep+" rightstep="+rightstep);
            //out.println("leftcost="+leftcost+" rightcost="+rightcost);
            //out.println("ans="+ans);
            int mi = Math.min(leftstep, rightstep);
            int ma = Math.max(leftstep, rightstep);
            ans = ans + mi*2 + ma;
            out.println(ans);
        }
    }

    

    static class InputReader{
        public BufferedReader br;
        public StringTokenizer tokenizer;
        
        public InputReader(InputStream ins) {
            br = new BufferedReader(new InputStreamReader(ins));
            tokenizer = null;
        }
        
        public String next(){
            while (tokenizer==null || !tokenizer.hasMoreTokens()) {
                try {
                tokenizer = new StringTokenizer(br.readLine());
                }catch(IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }
        
        public int nextInt() {
            return Integer.parseInt(next());
        }
    }
}

转载于:https://www.cnblogs.com/AWCXV/p/10427543.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值