1. 程式人生 > >[比賽|考試]nowcoder 小白月賽7

[比賽|考試]nowcoder 小白月賽7

mod 總結 scan 並且 opd 便是 mes 復制 滿足

牛客小白月賽7

比賽地址。本次比賽我切了8道(ACM賽制),rank(留一個坑)。

反思:剛入手ACM賽,光追求刺激了,沒有總結ACM賽制的經驗。是應該多提交》。。還是少提交。。。小白賽還有兩道不會的題呢。(其實是懶得推了)。所以以後刷題提手速,提腦速,提高做題時的緊張感(膜拜石室中學某大佬)。在打OI賽因為沒有實時的rank總會不緊張。。。(當然OI賽沒必要太緊張,要認真,以穩為準)在OI階段還是要以OI賽制為主,ACM賽制只是嘗嘗鮮罷了。

明天還有一場tg組的比賽,希望能把暴力分拿滿,正解寫出。

以下是部分題解


A.送分題

做水題就是在浪費時間,但是一場比賽要是沒有送分的簽到題,大家的比賽體驗就會很差。為了優化你的比賽體驗又不浪費你的讀題時間,我並不打算給你很復雜的故事背景,你只需要復制下面的代碼並選擇正確的語言提交即可通過此題。

#include<iostream>
using namespace std;
long long f(long long n)
{
    if (n < 20180001)
        return n + 2017;
    return f(f(n - 2018));
}
int main()
{
    long long n;
    cin >> n;
    cout << f(n) << endl;
    return 0;
}

題目描述tmd有誤,直接復制代碼無法通過本題。。。

找規律發現當\(n<20180000\)時,都是n+2017,否則都是20182017。代碼如下

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long n;
    cin >> n;
    if ( n >= 20180000)
        cout << 20180000 + 2017 <<endl;
    else
        cout << n + 2017 << endl;
    return 0;
}

B.自殺遊戲

Alice和Bob產生了不可調節的矛盾,於是他們相約一起玩一個自殺遊戲,輸的人就會從這個世界上消失。 遊戲開始時,Alice手上拿著一個定時炸彈,炸彈有個倒計時t。炸彈在t=0時刻會爆炸,此時手上拿著炸彈的人會從這個世界上消失。為了增加遊戲樂趣,他們約定每個人拿到炸彈後可以選擇將炸彈的時間調快d秒(d ∈ [a,b]),或者不調。每次交換炸彈會消耗1秒(假設調節炸彈時間不需要消耗時間)。 問題來了,如果雙方都足夠聰明,誰會活下去呢?輸入t a b輸出誰會存活。

令f[i]表示炸彈有i秒時候先手是否存活,f[i]可以由f[i-1],f[i-b-1]到f[i-a-1]內的數轉移,如果這些數裏有數是0那麽就f[i]=1,否則f[i]=0。(SG函數)本來想寫個樹狀數組維護但是寫炸了,然後看數據範圍發現暴力能過。

#include <bits/stdc++.h>
using namespace std;
int c[100010], t, a, b;
int main()
{
    scanf("%d%d%d", &t, &a, &b);
    for (int i = 1; i <= t; i++)
        if (c[i - 1] == 0)
            c[i] = 1;
        else
            for (int j = max(0, i - b - 1); j <= max(-1, i - a - 1); j++)
                if (c[j] == 0)
                {
                    c[i] = 1;
                    break;
                }
    printf("%s\n", (c[t]) ? "Alice" : "Bob");
    return 0;
}

C.誰是神射手

有一天,MWH突然來了興致,想和CSL比比誰槍法好。於是他們找來了一個瓶子,比比看誰先打中這個瓶子。 給定MWH的命中率\(\alpha\%\)和CSL的命中率\(\beta\%\)。 兩人輪流射擊,MWH先手,問誰獲勝的概率大?設\(f(\alpha,\beta)\)代表先手獲勝的概率(這裏認為他們倆是[0,1]的實數),那麽容易得到式子:\(f(\alpha,\beta)=\alpha+(1-\alpha)*(1-\beta)*f(\alpha,\beta)\),那麽我們亂推推就能得到\((-\alpha*\beta+\alpha+\beta)f(\alpha,\beta)=\alpha\),那麽\(\displaystyle f(\alpha,\beta)=\frac{\alpha}{-\alpha*\beta+\alpha+\beta}\)。令\(f(\alpha,\beta)=0.5\)得到\(-\alpha*\beta+\alpha+\beta=2\alpha\),然後再亂推推就得到就像程序中的結論。()懶得推了

#include <bits/stdc++.h>
using namespace std;

int alpha, beta;

double work(double a, double b)
{
    return a + (1 - a) * (1 - b) * work(a, b);
}

int main()
{
    cin >> alpha >> beta;
    int l = 100 * alpha;
    int r = 100 * beta - alpha * beta;
    if (l < r)
        cout << "CSL" << endl;
    if (l == r)
        cout << "equal" << endl;
    if (l > r)
        cout << "MWH" << endl;
    return 0;
}

D.明七暗七

今天是個特殊的日子,CSL和他的小夥伴們圍坐在一張桌子上玩起了明七暗七的遊戲。遊戲規則是這樣的: 一個人報出一個起始數,接下來按照逆時針的順序輪流報數,如果碰到數是7的倍數或含有7,則拍手,下一個人接著報數。直到有一個人報錯了數字或者沒有及時拍手為止。 玩遊戲嘛,當然得有懲罰。這麽簡單的遊戲對CSL的學霸小夥伴而言實在是太無腦了,輕輕松松數到上萬根本不在話下。但是對於數學是體育老師教的CSL來說,實在是太難了。快幫他算算什麽時候應該拍手吧。

不會做

E.Applese的超能力

Applese有個神奇的能力,TA可以把m個硬幣融合成1個硬幣,是不是很厲害。現在Applese有n個硬幣,TA想把這個n個硬幣融合成1個,請問他能完成嗎?

考慮Huffman編碼時補全節點的情況:\(n\equiv1\pmod{m-1}\)。所以只需要判斷這個式子是否成立就行了。

註意特殊的情況:m=1.此時你是無法融合的,所以當n=1輸出Yes,否則No

m=2.此時你可以xjb融合,最後肯定能融合出1個硬幣。直接輸出Yes

#include <bits/stdc++.h>
using namespace std;

int main()
{
    long long n, m;
    cin >> n >> m;
    if (m == 1)
        cout << ((n == 1) ? "Yes" : "No") << endl;
    else if (m == 2)
        cout << "Yes" << endl;
    else
    cout << ((n % (m - 1) == 1) ? "Yes" : "No") << endl;
    return 0;
}

F.BFS

Bob在學習了DFS後,自己又發明了一種新的搜(luan)索(gao)方法,叫做BFS(Bobby First Search)。 這種搜索被定義為:在一個字符串中,從前向後查找第一個子串"Bob"出現的位置。(不區分大小寫)

用STL水過。先轉換一下大小寫,然後直接調用find即可。(偷個懶寫個c++11的auto)

#include <bits/stdc++.h>
using namespace std;

int main()
{
    string str;
    cin >> str;
    for (string::iterator i = str.begin(); i != str.end(); i++)
    {
        if (isupper(*i))
            (*i) = tolower(*i);
    }
    auto res = str.find("bob");
    if (res == string::npos)
        cout << -1 << endl;
    else
        cout << res << endl;
    return 0;
}

G.CSL分蘋果

CSL手上有n個蘋果,第i個蘋果的質量是wi,現在他想把這些蘋果分給他的好朋友wavator和tokitsukaze。但是CSL為了不讓他們打架,根據質量決定盡量地均分成兩堆分給他們。現在CSL想知道到底給每個人分多少質量的蘋果。註意:蘋果不能劈開來,並且如果不能正好均分,tokitsukaze小姐姐會拿到重的那一堆。

dp。令f[i]表示是否能組成質量為i的,每次輸入就轉移一下就行了。

從總質量/2開始枚舉(向上/向下都行),直到找到一個f[i]\neq0輸出解就行。

H.CSL的校園卡

今天是陽光明媚,晴空萬裏的一天,CSL早早就高興地起床走出寢室到校園裏轉悠。 但是,等到他回來的時候,發現他的校園卡不見了,於是他需要走遍校園尋找它的校園卡。CSL想要盡快地找回他掉的校園卡,於是便求助於OneDay幫他一起找。 OneDay和CSL在同一已知的地點出發,並以相同的速度(1格/秒)搜索校園,試求兩人走遍校園的最短時間。輸入描述:第一行為兩個整數n,m(1 ≤ n, m ≤ 4),表示地圖的大小。接下來是n行m列的地圖:X表示障礙物,S表示起點,O表示空地。障礙物不能直接經過,數據保證所有空地是可達的,起點有且只有一個。輸出描述:輸出一個整數表示兩人共同走遍校園所需的最少時間。

不會

I.新建 Microsoft Office Word 文檔

CSL正在學習《計算機辦公自動化》文件的建立與刪除。 CSL發現,當他新建一個word文檔時,會得到一個名為"新建 Microsoft Office Word 文檔.doc"的文件,再新建一個,則名為"新建 Microsoft Office Word 文檔(2).doc",再新建,便是"新建 Microsoft Office Word 文檔(3).doc"。不斷新建,編號不斷遞增。倘若他已經新建了三個文檔,然後刪除了"新建 Microsoft Office Word 文檔(2).doc",再新建一個就又會得到一個"新建 Microsoft Office Word 文檔(2).doc"。 嚴格來說,Windows在每次新建文檔時,都會選取一個與已有文件編號不重復的最小正整數作為新文檔的編號。 現在,請你編程模擬以上過程,支持以下兩種操作: New:新建一個word文檔,反饋新建的文檔的編號; Delete id:刪除一個編號為id的word文檔,反饋刪除是否成功。 初始時一個文件都沒有,"新建 Microsoft Office Word 文檔.doc"的編號算作1。第一行一個正整數n表示操作次數,接下來n行,每行表示一個操作。若該行為"New",則表示新建,為:Delete id"則表示要刪除編號為id的文檔,其中id為一個正整數。操作按輸入順序依次進行。操作次數不超過100000,刪除編號的數值不超過100000。輸出描述:對於輸入的每一個操作,輸出其反饋結果。對於新建操作,輸出新建的文檔的編號;對於刪除操作,反饋刪除是否成功:如果刪除的文件存在,則刪除成功,輸出"Successful",否則輸出"Failed"。

我的思路是用一個平衡樹(stl的set)維護當前存在的文件,用一個小根堆(stl的priority_queue)維護被刪除的文件。

每次新建文件,在小根堆查詢是否有數,如果沒有就新開一個數。

每次刪除文件,在平衡樹判斷是否存在,如果存在就把文件從平衡樹扔到小根堆裏,否則輸出failed

#include <bits/stdc++.h>
using namespace std;

set<int> s;
priority_queue<int, vector<int>, greater<int> > q;

int main()
{
    int n;
    cin >> n;
    string str;
    int opd;
    int ptr = 0;
    for (int i = 1; i <= n; i++)
    {
        cin >> str;
        if (str == "New")
        {
            if (!q.empty())
            {
                int x = q.top();
                q.pop();
                s.insert(x);
                cout << x << endl;
            }
            else
            {
                s.insert(++ptr);
                cout << ptr << endl;
            }
        }
        if (str == "Delete")
        {
            cin >> opd;
            if (s.find(opd) != s.end())
            {
                s.erase(opd);
                q.push(opd);
                cout << "Successful" << endl;
            }
            else
            {
                cout << "Failed" << endl;
            }
        }
    }
    return 0;
}

J.方格填色

給一個m x n的方格,Applese想要給方格填上顏色,每個格子可以是黑色或者白色。他要求左右相鄰兩格不能同為白色且相鄰兩列不能全為黑色。 求滿足條件的方案數。(1 ≤ m ≤ 5, 1 ≤ n ≤ 10的18次方)。

f[i][j]表示某一長度的序列,以狀態為i開頭,狀態為j結尾的序列的情況數量。(狀態在[0,2^m)之間。)

然後呢可以\(O(n*(2^m)^2)\)遞推一下,但是因為這個遞推滿足結合律,可以用快速冪加速。(不知道這個叫不叫矩陣快速冪),但是一次計算是\(O((2^m)^4)\)的????反正我tmAC了。。。

#include <bits/stdc++.h>
#define p 1000000007
using namespace std;

struct statement
{
    long long f[32][32];
    statement(){memset(f, 0, sizeof(f));}
};

long long maxn;

statement operator*(const statement &a, const statement &b)
{
    statement ans;
    for (int lmid = 0; lmid <= maxn; lmid++)
        for (int rmid = 0; rmid <= maxn; rmid++)
        {
            if ((lmid != 0 || rmid != 0) && ((lmid & rmid) == 0))
            {
                for (int l = 0; l <= maxn; l++)
                    for (int r = 0; r <= maxn; r++)
                    {
                        ans.f[l][r] += 1LL * a.f[l][lmid] * b.f[rmid][r] % p;
                        ans.f[l][r] %= p;
                    }
            }
        }
    return ans;
}

statement fast_pow(statement x, long long y)
{
    statement ans;
    for (int i = 0; i <= maxn; i++)
        ans.f[i][i] = 1;
    while (y > 0)
    {
        if (y & 1)
            ans = ans * x;
        x = x * x;
        y >>= 1;
    }
    return ans;
}

int main()
{
    long long n, m;
    cin >> m >> n;
    maxn = (1LL << m) - 1;
    statement ans;
    for (int i = 0; i <= maxn; i++)
        ans.f[i][i] = 1;
    ans = fast_pow(ans, n - 1);
    long long res = 0;
    for (int l = 0; l <= maxn; l++)
        for (int r = 0; r <= maxn; r++)
            (res += ans.f[l][r]) %= p;
    cout << res << endl;
    return 0;
}

[比賽|考試]nowcoder 小白月賽7