NOIP2016 模拟赛-帕秋莉 解题报告

【问题描述】

一天帕秋莉又在考虑如何加强魔法咒语的威力。帕秋莉的魔法咒语是一个仅有大写字母
组成的字符串,我们考虑从’A’到’Z’分别表示 0 到 25 的数字,于是这个魔法咒语就可以看作一个 26 进制数。帕秋莉通过研究发现,如果一个魔法咒语所代表的数能够整除 10进制数 M 的话,就能够发挥最大的威力。若当前的魔法咒语并不能整除 M,帕秋莉只会将其中两个字符的位置交换,尽量让它能够被 M 整除,当然由于某些咒语比较特殊,无论怎么改变都不能达到这个目的。请你计算出她能否只交换两个字符就让当前咒语被 M 整除。(首位的’A’为前导 0)。

【输入】

第 1 行:1 个字符串,长度不超过 L。
第 2 行:1 个正整数,M。

【输出】

第 1 行:用空格隔开的 2 个整数,输出时先输位置靠前的那个。
如果存在多种交换方法,输出字典序最小的,比如 1 3 和 1 5 都可以达到目的,就输出
1 3;1 3 和 2 4 都行时也输出 1 3。
注意字符串下标从左到右依次为 1 到 L 开始。如果初始魔法咒语已经能够整除 M,输
出”0 0”;若无论如何也不能到达目的输出”-1 -1”。

【输入输出样例】

Input Output
PATCHOULI
16
4 9

【数据规模】

对于 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

【题解】

这道题看起来像一个模拟,可是仔细一想,直接模拟的复杂度是O(N^3),对于2000的点来说,是无法AC掉的。我们可以对模拟加一个优化,省去交换两个字符后重新扫描计算咒语的步骤,直接计算交换所带来的值的变化,因为位数都是不变的,所以O(1)的计算完全可行。

【代码】
#include
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define INF 0x7ffffff
#define clear(s,z) memset(s,z,sizoef(s))
#define copy(s,z) memcpy(s,z,sizeof(s))
using namespace std;
const int maxn=2e5+20;

int n,a[maxn],m,s[maxn],S;

void init()
{
    char ch[maxn];
    gets(ch);n=strlen(ch);for(int i=1;i<=n;i++)a[i]=ch[i-1]-65;
    scanf("%d",&m);
    s[n]=1;
    for(int i=n-1;i>=1;i--)s[i]=s[i+1]*26%m;
    for(int i=1;i<=n;i++)S=(S+s[i]*a[i])%m;
    if(S==0)
    {
        printf("0 0\n");
        exit(0);
    }
}

void doing()
{
    for(int i=1;i<=n-1;i++)
        for(int j=i+1;j<=n;j++)
        {
            int sum=S;
            sum=(sum+(a[i]-a[j])*s[j]+(a[j]-a[i])*s[i])%m;
            if(sum==0){
                printf("%d %d",i,j);
                return;
            }
        }
    printf("-1 -1");
}

int main()
{
    freopen("patchouli.in","r",stdin);
    freopen("patchouli.out","w",stdout);
    init(); 
    doing();
    return 0;
}

你可能感兴趣的:(题解,算法竞赛,NOIP模拟赛)