字符串的进制
题目描述:
有一个长度为 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; }