计蒜客 2020 蓝桥杯大学 B 组省赛模拟赛(一)字符串

题目描述:

有一个长度为 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

样例输入

NETTLE
35

样例输出

1 2

样例解释

交换 N 和第一个 E 。

解题报告:

1:可以用一个数组将26的几次方存储。可以反着处理。

2:用O(n)的时间求出sum,后面每次交换字母,只需要将之前的贡献减掉,加上新的。具体可以看代码。

3:每次取模要使用sum = (sum%mod+mod)%mod,防止负数,爆数据范围对答案的影响。

4:代码中从0到 len-1处理的,输出答案时要将答案加上1。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2000+10;
ll mod, dic[N];
char ss[N];
int main(){
    scanf("%s%lld", ss, &mod);
    ll len = strlen(ss), x = 1, sum = 0;
    for(ll i=len-1; i>=0; --i)
        dic[i] = x, sum += x*(ss[i]-'A'), sum %= mod, x = x*26%mod;
    if(!sum){
        printf("0 0\n");
        return 0;
    }
    for(ll i=0; i<len; ++i){
        for(ll j=i+1; j<len; ++j){
            ll ans = sum;//这里要特别注意=.=
            ans = ans-dic[i]*(ss[i]-'A')-dic[j]*(ss[j]-'A');
            ans = ans+dic[i]*(ss[j]-'A')+dic[j]*(ss[i]-'A'), ans = (ans%mod+mod)%mod;
            if(!ans){
                printf("%lld %lld\n", i+1, j+1);
                return 0;
            }
        }
    }
    printf("-1 -1\n");
    return 0;
}
发布了115 篇原创文章 · 获赞 3 · 访问量 5565

猜你喜欢

转载自blog.csdn.net/jun_____/article/details/104044913