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個小寫字母。定義回文字符串為正序和逆序相同的字符串榄鉴。求解比該字符串小(按照字典順序)的回文字符串有多少個轰坊?(這個數(shù)字會很大跺撼,因此輸出其對10^9+7取模)

輸入

第一行為T敛摘,測試的個數(shù)。
以下每個測試有2行习贫,前一行為字符串長度N和字母數(shù)量K逛球;
后一行是這個字符串S。

輸出

輸出格式為 Case #x: y苫昌,表示第x個測試(x從1編號)比該字符串小的回文字符串有y個颤绕。

數(shù)據(jù)范圍

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 (基礎(chǔ))

對于長度為N的回文字符串,只需考慮前一半即長度范圍在(N+1)/2的情況祟身。
對于字符串的第0個字符奥务,比'a'的ASCII碼每大1個,就意味著后面從第1到(N+1)/2的下標(biāo)范圍字符任意取值都滿足袜硫,因此第0個字符和S[0]不相等的情況下會產(chǎn)生(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]相等時闯睹,判斷輸入給定的字符串比這時候的回文字符串大小,如果輸入更大的話担神,那么最后的結(jié)果再加1楼吃。
數(shù)據(jù)較大,需要使用long long的類型妄讯,最后輸出的結(jié)果需要對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;
}

按照這個算法,時間復(fù)雜度為O(n^2)捞挥,樣例和第一個測試集可以通過浮创,但是在第二個測試集上會TLE,因此還需要對時間進(jìn)行優(yōu)化砌函。

解法2 (時間優(yōu)化)

由于上面的算法在計算字符串的時候需要反復(fù)計算K的高次冪斩披,而這期間K是不變的,因此采用秦久韶算法對K的次方進(jìn)行優(yōu)化讹俊,改寫成多項(xiàng)式相乘然后再相加垦沉,同時在每一步相乘之前都對10^9+7取模,這樣時間復(fù)雜度可以減到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;
}

使用改進(jìn)后的算法在兩個測試集都可以通過厕倍。

括弧:還有一種更直觀的理解方式贩疙,就是把這個K看做base讹弯,然后把字符串S看做K進(jìn)制的數(shù)(K≤26)况既,只需要把S轉(zhuǎn)換為10進(jìn)制數(shù)即可快速得到求解。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末组民,一起剝皮案震驚了整個濱河市棒仍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌臭胜,老刑警劉巖莫其,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異耸三,居然都是意外死亡乱陡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門仪壮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來憨颠,“玉大人,你說我怎么就攤上這事睛驳±有模” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵乏沸,是天一觀的道長淫茵。 經(jīng)常有香客問我,道長蹬跃,這世上最難降的妖魔是什么匙瘪? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蝶缀,結(jié)果婚禮上丹喻,老公的妹妹穿的比我還像新娘。我一直安慰自己翁都,他們只是感情好碍论,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著柄慰,像睡著了一般鳍悠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坐搔,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天藏研,我揣著相機(jī)與錄音,去河邊找鬼概行。 笑死蠢挡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播业踏,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼禽炬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了勤家?” 一聲冷哼從身側(cè)響起瞎抛,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎却紧,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胎撤,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晓殊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了伤提。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巫俺。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肿男,靈堂內(nèi)的尸體忽然破棺而出介汹,到底是詐尸還是另有隱情,我是刑警寧澤舶沛,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布嘹承,位于F島的核電站,受9級特大地震影響如庭,放射性物質(zhì)發(fā)生泄漏叹卷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一坪它、第九天 我趴在偏房一處隱蔽的房頂上張望骤竹。 院中可真熱鬧,春花似錦往毡、人聲如沸蒙揣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽懒震。三九已至,卻和暖如春惩阶,著一層夾襖步出監(jiān)牢的瞬間挎狸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工断楷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锨匆,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像恐锣,于是被迫代替她去往敵國和親茅主。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容