Google kick Start 2021 Round C 解题报告 (C语言)

(1) Smaller Strings

You are given an integer K and a string S of length N, consisting of lowercase letters from the first K letters of the English alphabet. Find the number of palindrome strings of length N which are lexicographically smaller than S and consist of lowercase letters from the first K letters of the English alphabet.

A string composed of ordered letters a1,a2,…,an is lexicographically smaller than another string of the same length b1,b2,…,bn if ai<bi, where i is the first index where characters differ in the two strings. For example, the following strings are arranged in lexicographically increasing order: aaa, aab, aba, cab.

A palindrome is a string that is the same written forwards and backwards. For example, anna, racecar, aaa and x are all palindromes, while ab, frog and yoyo are not.

As the number of such strings can be very large, print the answer modulo 10^9+7.

问题简述

给定字符串长度为N,仅包含字母表上的前K个小写字母。定义回文字符串为正序和逆序相同的字符串。求解比该字符串小(按照字典顺序)的回文字符串有多少个?(这个数字会很大,因此输出其对10^9+7取模)

输入

第一行为T,测试的个数。
以下每个测试有2行,前一行为字符串长度N和字母数量K;
后一行是这个字符串S。

输出

输出格式为 Case #x: y,表示第x个测试(x从1编号)比该字符串小的回文字符串有y个。

数据范围

Memory limit: 1 GB.
1≤T≤100.
The string S consists of lowercase letters from the first K letters of the English alphabet.

Test Set 1

Time limit: 20 seconds.
1≤N≤8.
1≤K≤5.

Test Set 2

Time limit: 10 seconds.
1≤N≤10^5.
1≤K≤26.

解法1 (基础)

对于长度为N的回文字符串,只需考虑前一半即长度范围在(N+1)/2的情况。
对于字符串的第0个字符,比'a'的ASCII码每大1个,就意味着后面从第1到(N+1)/2的下标范围字符任意取值都满足,因此第0个字符和S[0]不相等的情况下会产生(S[0]-'a')\times K^{(N+1)/2-1}种可能的字符串。
而第0个字符和S[0]相等的情况下,考虑S[1]同样可以得到(S[1]-'a')*\times K^{(N+1)/2-2}种可能的字符串。
以此类推,直到S[(N+1)/2-1]时,首先有S[(N+1)/2-1]-'a'种可能,然后在S[(N+1)/2-1]相等时,判断输入给定的字符串比这时候的回文字符串大小,如果输入更大的话,那么最后的结果再加1。
数据较大,需要使用long long的类型,最后输出的结果需要对10^9+7取模。

#include <stdio.h>
typedef long long int64;

int64 power(int x, int y)
{
    int64 s = 1;
    while (y-- > 0)
        s *= x;
    return s;
}

int main()
{
    int t = 0;
    scanf("%d", &t);
    for (int c = 0; c < t; c++)
    {
        int m = 0, k = 0;
        scanf("%d %d", &m, &k);
        int n = (m + 1) >> 1;
        char s[100001];
        scanf("%s", s);
        int64 summer = 0;
        for (int i = 0; i < n; i++)
            summer += (int64)(s[n - i - 1] - 'a') * power(k, i);

        int ckpt = -1;
        for (int i = m - n - 1; i >= 0; i--)
            if (s[i] != s[m - i - 1])
            {
                ckpt = i;
                break;
            }
        if (ckpt >= 0)
            if (s[ckpt] < s[m - ckpt - 1])
                summer++;
        summer = summer % 1000000007;
        printf("Case #%d: %lld\n", c + 1, summer);
    }
    return 0;
}

按照这个算法,时间复杂度为O(n^2),样例和第一个测试集可以通过,但是在第二个测试集上会TLE,因此还需要对时间进行优化。

解法2 (时间优化)

由于上面的算法在计算字符串的时候需要反复计算K的高次幂,而这期间K是不变的,因此采用秦久韶算法对K的次方进行优化,改写成多项式相乘然后再相加,同时在每一步相乘之前都对10^9+7取模,这样时间复杂度可以减到O(n)。

#include <stdio.h>
typedef long long int64;
const int mod = 1e9 + 7;

int main()
{
    int t = 0;
    scanf("%d", &t);
    for (int c = 0; c < t; c++)
    {
        int m = 0, k = 0;
        scanf("%d %d", &m, &k);
        int n = (m + 1) >> 1;
        char s[100001];
        scanf("%s", s);
        int64 summer = 0;
        for (int i = 0; i < n; i++)
        {
            summer *= k;
            summer += s[i] - 'a';
            summer %= mod;
        }

        int ckpt = -1;
        for (int i = m - n - 1; i >= 0; i--)
            if (s[i] != s[m - i - 1])
            {
                ckpt = i;
                break;
            }
        if (ckpt >= 0)
            if (s[ckpt] < s[m - ckpt - 1])
                summer++;
        summer %= mod;
        printf("Case #%d: %lld\n", c + 1, summer);
    }
    return 0;
}

使用改进后的算法在两个测试集都可以通过。

括弧:还有一种更直观的理解方式,就是把这个K看做base,然后把字符串S看做K进制的数(K≤26),只需要把S转换为10进制数即可快速得到求解。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容