字符串的进制

题目描述:
有一个长度为 L 的字符串,每个字符是大写字母。如果我们把 A看做 0 ,B 看做 1,C看做 2... Z 看做 25,那么我们就得到了一个 26 进制的数字串。
我们可以对这个字符串做一个操作:将两个位置的字母进行交换。这样得到了一个新的数字串。
现在有一个十进制整数 M ,请判断是否可以通过做至多一次(可以不做)操作,使得得到的字符串是 M 的倍数。

输入格式

第一行一个只包含大写字母的字符串。

第二行一个整数 M 。

输出格式

如果初始串就可以,那么输出 “0 0”(不加引号)

如果通过一次操作可以,请输出交换的两个位置的标号(标号小的在前,从 1开始)。如果有多解,输出字典序最小的。

如果做不到,那么输出 “-1 -1”(不加引号)

数据范围

字符串长度为 L 。

对于 30% 的数据: 1≤L≤10,1≤M≤100

对于 50% 的数据:除前面 30% 外, 1≤L≤500,M=5 或 25或 26

对于 100% 的数据: 1≤L≤2,000,1≤M≤200,000

思路:先遍历字符串,找到每个字符,对于的十进制代表的位大小,并存入数组,且计算字符串的总大小 sum,寻找m的倍数字符串时,就遍历字符串,判断指到的元素 i 和元素 j ,用sum减去之前 i j位置时候的对应位大小乘以对应字符大小,加上交换后j i 位置对应位大小乘以对应字符大小,判断此时sum是否整除M。(不要一个一个从头计算字符串的sum,会超时)

#include <bits/stdc++.h>
using namespace std;
long long sum=0,m;
long long dic[2005];
string s;
bool change(int i,int j){
    long long all=sum;
    all=all-dic[i]*(s[i]-'A')-dic[j]*(s[j]-'A');     //先减去i j 位置的大小*字符大小 
    all=all+dic[i]*(s[j]-'A')+dic[j]*(s[i]-'A');     //再加上j i 位置的大小*字符大小 
    if(all%m==0) return true;
    else return false;
}
int main() {
    cin>>s>>m;
    long long x=1;
    int len=s.length();
    for(int i=len-1; i>=0;i--){                                   //字符串做成进制数,应该从后向前遍历                         
        dic[i] = x, sum += x*(s[i]-'A'), sum %= m, x = x*26%m;    //x 该位的大小,s[i]-'A' 该位的字符大小 
    }                                                             //此时位大小和字符大小一一对应,即dic[i] 必须和s[i]匹配 
    if(sum%m==0){                                                 
        cout<<"0 0";
    }
    else{
        for(int i=0;i<len-1;i++){                                //-->>下面从前向后遍历对应关系不能错 
            for(int j=i+1;j<len;j++){
                if(change(i,j)){
                    cout<<i+1<<" "<<j+1;
                    return 0;
                }
            }
        }
        cout<<-1<<" "<<-1;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/xusi/p/12391082.html