牛客小白月賽7
鏈接:https://www.nowcoder.com/acm/contest/190/A
來源:牛客網
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; }
輸入描述:
輸入一個整數n。(1 ≤ n ≤ 10
18
)
輸出描述:
輸出一個整數表示答案。
輸入
20182017
輸出
20182017
分析: 蠻有意思的簽到題. 直接交,肯定是可以A的. 不行看:
, 很真實的通過率.
我們穩妥點分析,(把代碼復制到本地,隨便輸入幾個數...)然後我們發現, n小於20180001時輸出n+2017 否則輸出20182017 就OK了.
#include<iostream> using namespace std; int main() { long long n; cin >> n;View Codeif (n < 20180001) cout << 2017 + n << endl; else cout << 20182017 << endl; return 0; }
鏈接:https://www.nowcoder.com/acm/contest/190/B
來源:牛客網
B.題目描述
Alice和Bob產生了不可調節的矛盾,於是他們相約一起玩一個自殺遊戲,輸的人就會從這個世界上消失。遊戲開始時,Alice手上拿著一個定時炸彈,炸彈有個倒計時t。炸彈在t=0時刻會爆炸,此時手上拿著炸彈的人會從這個世界上消失。為了增加遊戲樂趣,他們約定每個人拿到炸彈後可以選擇將炸彈的時間調快d秒(d ∈ [a,b]),或者不調。每次交換炸彈會消耗1秒(假設調節炸彈時間不需要消耗時間)。
問題來了,如果雙方都足夠聰明,誰會活下去呢?
輸入描述:
第一行有三個整數t,a,b,分別表示炸彈初始時刻的倒計時,可調節時間的範圍。(0 ≤ t ≤ 10^5,1 ≤ a ≤ b ≤ 10)
輸出描述:
若Alice存活則輸出"Alice",若Bob存活則輸出"Bob"。
輸入
6 3 4
輸出
Alice
說明
Alice只需要將炸彈調快3秒後再給Bob,Bob就會拿到一個2秒後爆炸的炸彈。
分析: 看到t的範圍不是很大,
所以我們可以假定一個狀態state[t]表示炸彈時間為t的存活狀態,
state[t]==1表示Alice在t時刻存活,Bob死亡,
state[t]==0表示在t時刻Alice死亡, Bob存活.
然後每次可以調控[a,b]的時間,同時傳遞炸彈需要1秒,
所以,我們的狀態可以這樣轉移:
當state[t-(b+1)]...state[t-(a+1)]存在一個state[x]==0時 state[t] = 1
或者 當 state[t-1]==0時 state[t] = 1
可以理解為: 如果時間為炸彈[t-1]或者[t-(b+1)]~[t-(a+1)]的遊戲的結果都是最優解了,而現在炸彈的時間增加了,所以如果在過去的一段區間出現Alice死亡的結局,那麽現在就可以翻轉這個結局了.
#include <cstdio> using namespace std; const int maxn = 1e5+500; bool living[maxn]; // living[t]==true表示t時刻Alice活,Bob死 int main() { int i, j, t, a, b; scanf("%d%d%d", &t, &a, &b); for (i=1; i<=t; ++i) { if (!living[i-1]) living[i] = true; // 表明上一次遊戲的最優解Alice死,Bob活,狀態轉移,當前遊戲的Alice活,Bod死 for (j=i-b-1; j<=i-a-1; ++j) { // 因為傳遞炸彈要用1秒 所以還要減一 if (j>=0 && !living[j]) { // 表明上一次遊戲的最優解有Alice死,Bob活,狀態轉移,當前遊戲的Alice活,Bod死 living[i] = true; break; } } } printf("%s\n", living[t] ? "Alice" : "Bob" ); return 0; }View Code
鏈接:https://www.nowcoder.com/acm/contest/190/C
來源:牛客網
C.題目描述
有一天,MWH突然來了興致,想和CSL比比誰槍法好。於是他們找來了一個瓶子,比比看誰先打中這個瓶子。 給定MWH的命中率和CSL的命中率。 兩人輪流射擊,MWH先手,問誰獲勝的概率大?輸入描述:
輸入兩個整數
和
,表示MWH和CSL的命中率。
.
輸出描述:
若MWH獲勝的概率大,則輸出"MWH"。 若CSL獲勝的概率大,則輸出"CSL",否則輸出"equal"。
輸入
100 100
輸出
MWH
輸入
0 100
輸出
CSL
分析: 很明顯的一道數學題. 所以推公式. 是不可能的. 我暴力計算不知道什麽東西...然後就過了....(應該是期望吧...大概..反正很玄學的過了...)
#include <cstdio> #include <cmath> int main() { double a, b; scanf("%lf%lf", &a, &b); a /= 100.0; b /= 100.0; double win1 = a, win2 = (1 - win1) * b; for (int i=1; i<=10000000; ++i) { win1 = win1 + a * (1 - win2); win2 = win2 + b * (1 - win1); } double eps = 1e-7; if (fabs(win1 - win2) <= eps) printf("equal\n"); else if (win1 > win2) printf("MWH\n"); else printf("CSL"); return 0; }View Code
鏈接:https://www.nowcoder.com/acm/contest/190/D
來源:牛客網
D.題目描述
今天是個特殊的日子,CSL和他的小夥伴們圍坐在一張桌子上玩起了明七暗七的遊戲。遊戲規則是這樣的:一個人報出一個起始數,接下來按照逆時針的順序輪流報數,如果碰到數是7的倍數或含有7,則拍手,下一個人接著報數。直到有一個人報錯了數字或者沒有及時拍手為止。
玩遊戲嘛,當然得有懲罰。這麽簡單的遊戲對CSL的學霸小夥伴而言實在是太無腦了,輕輕松松數到上萬根本不在話下。但是對於數學是體育老師教的CSL來說,實在是太難了。快幫他算算什麽時候應該拍手吧。
輸入描述:
輸入兩個整數m和n。(1 ≤ m, n ≤ 10^12)
輸出描述:
輸出一個整數,表示m以後第n個需要拍手的數字。
輸入
30 7
輸出
57
輸入
56 1
輸出
57
分析: 我們記[1..n]中含有7的或者可以被7整除的數字個數為a. 而我們要求得就是第m+a個含有7的或者可以被7整除的數字.
對於這種問題,我們應該很容易想到數位dp,
然後數位dp我們可以求 [1..n]中不含有7的且不可以被7整除的數字個數.
所以 [1..n]中含有7的或者可以被7整除的數字個數 = n - [1..n]中不含有7的且不可以被7整除的數字個數.
所以,我們求出 [1..n]中含有7的或者可以被7整除的數字個數 後,我們就可以二分我們的答案來求出數字了.
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; ll dp[20][8]; int digit[25]; ll dfs(int deep, ll state, bool lmt) { if (!deep) return state ? 1 : 0; if (!lmt && dp[deep][state]>=0) return dp[deep][state]; int i, up = lmt ? digit[deep] : 9; ll cnt = 0; for (i=0; i<=up; ++i) { if (i==7) continue; cnt += dfs(deep-1, (state*10+i)%7, lmt && i==up); } return lmt ? cnt : dp[deep][state]=cnt; } ll cal(ll num) { int k = 1; while (num) { digit[k++] = num % 10; num /= 10; } return dfs(k-1, 0, true); } int main() { ll n, m, left, right, mid, tmp; // printf("%d %d\n", 14-cal(14*1ll), cal(14)); while (~scanf("%lld%lld", &m, &n)) { memset(dp, -1, sizeof(dp)); left = 0; right = 1LL*1e18; tmp = m - cal(m); // while (left <= right) { mid = (left + right) / 2; if (mid-cal(mid) >= tmp+n) { right = mid - 1; } else { left = mid + 1; } } printf("%lld\n", left); } return 0; }View Code
鏈接:https://www.nowcoder.com/acm/contest/190/E
來源:牛客網
E.題目描述
Applese有個神奇的能力,TA可以把m個硬幣融合成1個硬幣,是不是很厲害。現在Applese有n個硬幣,TA想把這個n個硬幣融合成1個,請問他能完成嗎?輸入描述:
輸入兩個整數n,m(1 ≤ n, m ≤ 10^9)
輸出描述:
如果Applese能完成,輸出"Yes",否則輸出"No"。
輸入
10 7
輸出
No
分析: 我們發現...這是一道模擬題. 然後要註意死循環. 然後沒了.
#include<iostream> using namespace std; int main() { long long n, m; cin >> n >> m; long long lst = n; while (n && n!=1) { n = n / m + n % m; if (n == lst) break; lst = n; } if (n == 1) cout << "Yes" << endl; else cout << "No" << endl; return 0; }View Code
鏈接:https://www.nowcoder.com/acm/contest/190/F
來源:牛客網
F.題目描述
Bob在學習了DFS後,自己又發明了一種新的搜(luan)索(gao)方法,叫做BFS(Bobby First Search)。這種搜索被定義為:在一個字符串中,從前向後查找第一個子串"Bob"出現的位置。(不區分大小寫)
輸入描述:
輸入一個不含空格的字符串S(可能含有大小寫字母,數字)。(1 ≤ |S| ≤ 100)
輸出描述:
輸出一個數字,表示"Bob"第一次出現的位置(下標從0開始)。
如果沒有出現,則輸出"-1"。
輸入
Bobob
輸出
0
輸入
bobby
輸出
0
輸入
BFS
輸出
-1
分析: 沒啥好講的.
#include <cstdio> #include <cstring> #include <cctype> char str[128]; int main() { scanf("%s", str); for (int i=0; str[i]; ++i) str[i] = tolower(str[i]); int idx = strstr(str, "bob") - str; printf("%d\n", idx < 0 ? -1 : idx); return 0; }View Code
鏈接:https://www.nowcoder.com/acm/contest/190/G
來源:牛客網
G.題目描述
CSL手上有n個蘋果,第i個蘋果的質量是wi,現在他想把這些蘋果分給他的好朋友wavator和tokitsukaze。但是CSL為了不讓他們打架,根據質量決定盡量地均分成兩堆分給他們。現在CSL想知道到底給每個人分多少質量的蘋果。註意:蘋果不能劈開來,並且如果不能正好均分,tokitsukaze小姐姐會拿到重的那一堆。
輸入描述:
第一行輸入一個整數n(2 ≤ n ≤ 100),第二行n個整數,表示每個蘋果的質量wi(1 ≤ wi≤ 100)。
輸出描述:
輸出兩個整數,分別表示wavator和tokitsukaze得到的蘋果的質量。
輸入
3 2 2 2
輸出
2 4
分析: 這是一道比較經典的01背包問題.
思路是,把總質量除以二作為最大容量,每一個蘋果的花費和收益都是它的重量,然後就是一個裸的01背包.
為什麽這樣可以呢?
因為,它要兩個人的質量差盡量小,同時蘋果不能分割,所以把總質量的一半作為01背包的最大容量,然後盡可能的取最大質量.
然後答案很明顯就是我們要的.
(我才不會承認,,,,我寫不來01背包了...直接copy以前的01背包答案就扔上去了....
而且還是沒有優化的01背包...代碼有點醜..最後感謝出題人不殺)
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 128; int date[128]; int dp[124][10024]; int main() { int n, i, j, sum = 0; scanf("%d", &n); for (i=1; i<=n; ++i) { scanf("%d", date+i); sum += date[i]; } int tmp = sum; sum /= 2; for (i=1; i<=n; ++i) { for (j=1; j<=sum; ++j) { if (j>=date[i]) dp[i][j] = max(dp[i-1][j], dp[i-1][j-date[i]] + date[i]); else dp[i][j] = dp[i-1][j]; } } printf("%d %d\n", min(tmp - dp[n][sum], dp[n][sum]), max(tmp - dp[n][sum], dp[n][sum])); return 0; }View Code
鏈接:https://www.nowcoder.com/acm/contest/190/H
來源:牛客網
H.題目描述
今天是陽光明媚,晴空萬裏的一天,CSL早早就高興地起床走出寢室到校園裏轉悠。但是,等到他回來的時候,發現他的校園卡不見了,於是他需要走遍校園尋找它的校園卡。CSL想要盡快地找回他掉的校園卡,於是便求助於OneDay幫他一起找。
OneDay和CSL在同一已知的地點出發,並以相同的速度(1格/秒)搜索校園,試求兩人走遍校園的最短時間。
輸入描述:
第一行為兩個整數n,m(1 ≤ n, m ≤ 4),表示地圖的大小。接下來是n行m列的地圖:X表示障礙物,S表示起點,O表示空地。障礙物不能直接經過,數據保證所有空地是可達的,起點有且只有一個。
輸出描述:
輸出一個整數表示兩人共同走遍校園所需的最少時間。
輸入
3 4 XSOO OOXO OOOO
輸出
5
說明
輸入
2 3 XSX OOO
輸出
2
輸入
4 4 SOOO OOOO OOOO OOOO
輸出
8
分析: 很明顯的bfs....之前做了一個搜索入門的題..寫了半個多少小時..發現自己寫的不知道什麽東西....
然後自閉了.. 看的題解寫的.
我們發現n,m只有[1,4], 所以對於地圖的記錄,我們可以狀態壓縮,直接通過一個數來表示.
然後我們可以開一個 vis[1<<16][4][4][4][4] 數組來記錄 vis[地圖][x1][y1][x2][y2]
如果寫過一些搜索題,應該就很簡單了.
#include <cstdio> #include <queue> using namespace std; bool vis[1<<16][4][4][4][4]; int n, m; char _m[5][5]; struct nobe { int val; int x1; int y1; int x2; int y2; int step; nobe () { }; nobe (int xx1, int yy1, int xx2, int yy2, int vv, int ss) : x1(xx1), y1(yy1), x2(xx2), y2(yy2), val(vv), step(ss) { } }; inline int get(int x1, int y1, int x2, int y2, int val) { val |= (1 << ((x1 * m) + y1)); val |= (1 << ((x2 * m) + y2)); return val; } int dir[] = {1, 0, -1, 0, 1}; int bfs(nobe st) { queue<nobe> q; nobe now; int x1, y1, x2, y2, step, val, tmp; int ed = 0, i, j; for (i=0; i<n; ++i) { for (j=0; j<m; ++j) { ed |= (1 << (i * m + j)); } } q.push(st); while (!q.empty()) { now = q.front(); q.pop(); x1 = now.x1; y1 = now.y1; x2 = now.x2; y2 = now.y2; step = now.step; val = now.val; if (x1<0 || x1>=n || y1<0 || y1>=m) continue; if (x2<0 || x2>=n || y2<0 || y2>=m) continue; if (_m[x1][y1]==‘X‘) continue; if (_m[x2][y2]==‘X‘) continue; if (val == ed) return step; if (vis[val][x1][y1][x2][y2]) continue; vis[val][x1][y1][x2][y2] = true; for (i=1; i<5; ++i) { for (j=1; j<5; ++j) { tmp = get(x1+dir[i-1], y1+dir[i], x2+dir[j-1], y2+dir[j], val); q.push(nobe(x1+dir[i-1], y1+dir[i], x2+dir[j-1], y2+dir[j], tmp, step+1)); } } } return -1; } int main() { // freopen("E:\\input.txt", "r", stdin); int i, j; scanf("%d%d", &n, &m); int val, x, y; val = 0; for (i=0; i<n; ++i) { scanf("%s", _m[i]); for (j=0; j<m; ++j) { if (_m[i][j] == ‘X‘ || _m[i][j] == ‘S‘) val |= (1 << (i * m + j)); if (_m[i][j] == ‘S‘) { x = i; y = j; } } } printf("%d\n", bfs(nobe(x, y, x, y, val, 0))); return 0; }View Code
鏈接:https://www.nowcoder.com/acm/contest/190/I
來源:牛客網
I.題目描述
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"。
輸入
12 New New New Delete 2 New Delete 4 Delete 3 Delete 1 New New New Delete 4
輸出
1 2 3 Successful 2 Failed Successful Successful 1 3 4 Successful
分析: 我們可以把題意翻譯成:
我們開始有一個集合[1...n],
然後有2個操作,
1. New 輸出集合中的最小數,同時刪除這個最小數.
2. Delete num 查找集合中是否有這個數,如果有輸出Failed,否則輸出Successful,同把num插入到集合.
一個Set模擬的題.
#include <set> #include <cstdio> #include <cstring> using namespace std; char op[32]; int main() { int t, i, id; // freopen("E:\\input.txt", "r", stdin); scanf("%d", &t); set<int> se; for (i=1; i<=100500; ++i) se.insert(i); while (t--) { scanf("%s", op); if (op[0] == ‘N‘) { printf("%d\n", *se.begin()); se.erase(se.begin()); } else { scanf("%d", &id); if (se.find(id) != se.end()) printf("Failed\n"); else printf("Successful\n"), se.insert(id); } } return 0; }View Code
鏈接:https://www.nowcoder.com/acm/contest/190/J
來源:牛客網
題目描述
給一個m x n的方格,Applese想要給方格填上顏色,每個格子可以是黑色或者白色。他要求左右相鄰兩格不能同為白色且相鄰兩列不能全為黑色。求滿足條件的方案數。
輸入描述:
輸入兩個整數m, n。(1 ≤ m ≤ 5, 1 ≤ n ≤ 10^18)。
輸出描述:
1e9+7取模。
輸入
3 1
輸出
8
輸入
3 5
輸出
1640
輸入
5 5
輸出
351032
分析: 這道題我也是看題解和別人博客才明白的. 然後我覺得做法特別妙..如果沒有做過這種題,我覺得想不到.
我們發現題目中的限制: 左右不能有相鄰的白色, 兩列不能全為黑色. 都只與列有關,與行無關. 同時每一列都只有2^m中排列,m特別小.
所以我們可以用二進制來表示這一列的狀態, 我們白色用1來表示, 黑色用0表示.
例如當m=4時有一列: 白 黑 白 白 的排序, 就是 1011 ,這個我們用一個十進制數11來表示
然後如果一個狀態k可以由另一個狀態a轉移過來 那麽就需要滿足 (a&k)==0 && (a | k) (左右不能有相鄰的白色, 兩列不能全為黑色)
例如 1011 可以由 0100 或者 0000 等轉過來
然後我們可以定義f[第i列][當前狀態a]來表示轉移到第i列狀態a的方案數.
f[第i列][當前狀態] = sigma(f[第i-1列][可以轉移到當前狀態的狀態]). n特別大,我們用矩陣快速冪來做.
我就粘個題解的圖,當2*n時的矩陣
#include <cstdio> #include <iostream> using namespace std; typedef long long ll; const ll mod = 1e9+7; class Matrix { public: int r, c; ll mat[32][32]; ll *operator [] (int x) { return mat[x]; } Matrix operator * (const Matrix &a) const { Matrix res; res.r = r; res.c = a.c; int i, j, k; for (i=0; i<res.r; ++i) { for (j=0; j<res.c; ++j) { res[i][j] = 0; for (k=0; k<c; ++k) res[i][j] = (res[i][j] + mat[i][k] * a.mat[k][j] % mod) % mod; } } return res; } }mat, mat2; Matrix pwr(const Matrix &a, ll k) { Matrix base = a, r; int i, j; r.r = a.r; r.c = a.c; for (i=0; i<r.r; ++i) for (j=0; j<r.c; ++j) r[i][j] = i==j; while (k) { if (k & 1) r = r * base; base = base * base; k >>= 1; } return r; } int main() { int i, j; ll n, m; cin >> m >> n; mat.c = mat.r = (1 << m); mat2.c = 1; mat2.r = (1 << m); for (i=0; i<(1<<m); ++i) { mat2[i][0] = 1; for (j=0; j<(1<<m); ++j) { mat[i][j] = 1ll * (((i & j) == 0) && (i | j)); } } mat = pwr(mat, n-1); mat = mat * mat2; ll res = 0; for (i=0; i<(1<<m); ++i) { res = (res + mat[i][0]) % mod; } cout << res << endl; }View Code
牛客小白月賽7