T1 數字遊戲
題目描述
小 K 同學向小 P 同學發送了一個長度爲 的 01 字符串 來玩數字遊戲,小 P 同學想要知道字符串中究竟有多少個 。
注意:01 字符串爲每一個字符是 或者 的字符串,如“101”(不含雙引號)爲一個長度爲 的 01 字符串。
輸入格式
輸入只有一行,一個長度爲 的 01 字符串 。
輸出格式
輸出只有一行,包含一個整數,即 01 字符串中字符 的個數。
數據範圍
對於 % 的數據,保證輸入的字符全部爲 。
對於 % 的數據,輸入只可能包含字符 和字符 ,字符串長度固定爲 。
T1分析
送分題, 數據直接輸出 就可以,讀取一個字符串,遍歷一遍字符串,計數有多少個
當然這裏有個小公式 :
所以這裏可以直接輸出
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
cout << n % 9 << endl;
return 0;
}
T2 公交換乘
題目描述
著名旅遊城市 B 市爲了鼓勵大家採用公共交通方式出行,推出了一種地鐵換乘公交車的優惠方案:
-
在搭乘一次地鐵後可以獲得一張優惠票,有效期爲 分鐘,在有效期內可以消耗這張優惠票,免費搭乘一次票價不超過地鐵票價的公交車。在有效期內指開始乘公交車的時間與開始乘地鐵的時間之差小於等於 分鐘,即
-
搭乘地鐵獲得的優惠票可以累積,即可以連續搭乘若干次地鐵後再連續使用優惠票搭乘公交車。
-
搭乘公交車時,如果可以使用優惠票一定會使用優惠票;如果有多張優惠票滿足條件,則優先消耗獲得最早的優惠票。
現在你得到了小軒最近的公共交通出行記錄,你能幫他算算他的花費嗎?
輸入格式
輸入的第一行包含一個正整數 ,代表乘車記錄的數量。
接下來的 行,每行包含 個整數,相鄰兩數之間以一個空格分隔。第 行的第 個整數代表第 條記錄乘坐的交通工具, 代表地鐵, 代表公交車;第 個整數代表第 條記錄乘車的票價 ;第三個整數代表第 條記錄開始乘車的時間 (距 時刻的分鐘數)。
我們保證出行記錄是按照開始乘車的時間順序給出的,且不會有兩次乘車記錄出現在同一分鐘。
輸出格式
輸出有一行,包含一個正整數,代表小軒出行的總花費。
數據範圍
對於 % 的數據,,。
另有 % 的數據,, 都相等。
另有 % 的數據,, 都相等。
對於 % 的數據,,,。
T2分析
第二題,一個模擬題,不過這道題的模擬比往年的都要難一些,當然也沒有特別難
讀題需要仔細讀,不要讀錯了
接下來就是如何做的問題了,這道題其實非常簡單,對於每次乘車記錄,如果是乘地鐵,那就獲得一張贈票,如果是公交,那就在所有可以用的贈票裏找一張離現在最遠的用掉
那麼如果暴力去找贈票的話複雜度是 顯然會超時
所以這裏需要一些優化
思考一下,坐車的記錄是按順序來的,那也就是說手裏拿到贈票的時間是按時間排好的,那隨着時間的推移,顯然能用的贈票必然是贈票序列中的連續的一段
所以這就很像我們學習過的一種數據結構——隊列
贈票全部從隊尾加入隊列,隊頭彈出所有過期的贈票,每次在隊列中找一下所有可用的贈票,因爲這個隊列的長度不可能超過 ,所以不會超時
這裏因爲直接使用 的隊列我們並不能非常方便的處理票用沒用過的問題,所以我們還是用數組來模擬
#include <iostream>
using namespace std;
const int MAXN = 100005;
struct Ticket {
//贈票的價格,最晚使用時間和是否需用過
int price, time, used;
} q[MAXN];//贈票盒子
int head, tail, n, cost;
int main() {
cin >> n;
for (int i = 0; i < n; ++i) {
int op, price, time;
//輸入每次坐車的種類,價格和發車時間
cin >> op >> price >> time;
if (op == 0) {
cost += price;
q[tail].time = time + 45;
q[tail++].price = price;
} else {
while (head < tail && q[head].time < time) {
head++;
}
bool found = false;//表示是否有合適的贈票,先假設沒有
for (int j = head; j < tail; ++j) {
if (q[j].price >= price && q[j].used == 0) {
//如果價格合適,並且沒用過,標記找到了,這張票標記用過
found = true;
q[j].used = 1;
break;
}
}
//如果沒找到合適的贈票,老老實實花錢買吧
if (!found) cost += price;
}
}
cout << cost << endl;
return 0;
}
T3 紀念品
題目描述
小偉突然獲得一種超能力,他知道未來 天 種紀念品每天的價格。某個紀念品的價格是指購買一個該紀念品所需的金幣數量,以及賣出一個該紀念品換回的金幣數量。
每天,小偉可以進行以下兩種交易 無限次:
-
任選一個紀念品,若手上有足夠金幣,以當日價格購買該紀念品;
-
賣出持有的任意一個紀念品,以當日價格換回金幣。
每天賣出紀念品換回的金幣可以立即用於購買紀念品,當日購買的紀念品也可以當日賣出換回金幣。當然,一直持有紀念品也是可以的。
天之後,小偉的超能力消失。因此他一定會在第 天賣出所有紀念品換回金幣。
小偉現在有 枚金幣,他想要在超能力消失後擁有儘可能多的金幣。
輸入格式
第一行包含三個正整數 ,相鄰兩數之間以一個空格分開,分別代表未來天數 ,紀念品數量 ,小偉現在擁有的金幣數量 。
接下來 行,每行包含 個正整數,相鄰兩數之間以一個空格分隔。第 行的 個正整數分別爲 ,其中 表示第 天第 種紀念品的價格。
輸出格式
輸出僅一行,包含一個正整數,表示小偉在超能力消失後最多能擁有的金幣數量。
數據規模與約定
對於 % 的數據,。
對於 % 的數據,,,,所有價格 $10 \leq P_{i,j} \leq 100 $。
對於 % 的數據,,。
對於 % 的數據,,$N \leq 100 $。
對於 % 的數據,,,,所有價格 $1 \leq P_{i,j} \leq 10^4 $,數據保證任意時刻,小明手上的金幣數不可能超過 。
T3分析
首先前 的分數是送的…只有一天所以輸出 就可以了,再怎麼樣白送的分數要拿到…
然後這道題難點在於如何考慮買物品賣物品的問題
其實題目裏多次強調,一件物品可以隨時賣出,隨時買進,買進賣出沒有任何限制
所以這道題的關鍵點就在這裏——我們沒有必要考慮買進物品後,這個物品我們要拿幾天賣掉,完全可以所有物品的操作都是今天買進明天賣出,我們每天先把手裏有的物品全部賣光,再考慮今天要買什麼
也就是說持有一件物品三天可以看成——第一天買進,第二天賣出後再買進,第三天賣出後再買進
只要考慮到上面這一點後,我們的問題就會被簡化爲,今天我們有 元錢,知道每個物品今天的價格和明天的價格,物品數量無限,問今天買進明天賣出後最多能獲得多少錢
那麼其實這個問題就是一個非常經典的問題了——完全揹包
我們把每個物品的花費看做今天物品買入的價格,每個物品的價值就是這件物品 ,也就是說對第 天,第 件物品,構造 物品數量無限,我們總共有 元錢,要獲得最高的價值,那不就是一個完全揹包嗎?
所以這道題題目就完成了
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 105;
const int M = 1e4 + 5;
int t, n, m;
int a[N][N], f[M];
int main() {
scanf("%d%d%d", &t, &n, &m);
for (int i = 1; i <= t; ++i){
for (int j = 1; j <= n; ++j){
scanf("%d", &a[i][j]);
}
}
for (int i = 1; i <= t; ++i) {
memset(f, 0, sizeof f);
for (int j = 1; j <= n; ++j){
for (int k = a[i][j]; k <= m; ++k){
f[k] = max(f[k], f[k - a[i][j]] + a[i+1][j] - a[i][j]);
}
}
m = max(m, f[m] + m);
}
printf("%d\n", m);
return 0;
}
T4 加工零件
題目描述
凱凱的工廠正在有條不紊地生產一種神奇的零件,神奇的零件的生產過程自然也很神奇。工廠裏有 位工人,工人們從 ~ 編號,某些工人之間存在雙向的零件傳送帶。保證每兩名工人之間最多隻存在一條傳送帶。
如果 號工人想生產一個被加工到第 階段的零件,則所有與 號工人有傳送帶直接相連的工人,都需要生產一個被加工到第 階段的零件(但 號工人自己無需生產第 階段的零件)。
如果 號工人想生產一個被加工到第 階段的零件,則所有與 號工人有傳送帶直接相連的工人,都需要爲 號工人提供一個原材料。
軒軒是 號工人。現在給出 張工單,第 張工單表示編號爲 的工人想生產一個第 階段的零件。軒軒想知道對於每張工單,他是否需要給別人提供原材料。他知道聰明的你一定可以幫他計算出來!
輸入格式
第一行三個正整數 和 ,分別表示工人的數目、傳送帶的數目和工單的數目。
接下來 行,每行兩個正整數 和 ,表示編號爲 和 的工人之間存在一條零件傳送帶。保證 。
接下來 行,每行兩個正整數 和 ,表示編號爲 的工人想生產一個第 階段的零件。
輸出格式
共 行,每行一個字符串“Yes”或者“No”。如果按照第 張工單生產,需要編號爲 的軒軒提供原材料,則在第 行輸出“Yes”;否則在第 行輸出“No”。注意輸出不含引號。
數據範圍
共 20 個測試點。
。
測試點 ~ ,,,。
測試點 ~ ,,,。
測試點 ~ ,,。
測試點 ~ ,,。
測試點 ~ ,,。
T4分析
這道題目的題意比較複雜,大概的意思就是說
如果有兩個人 相連,那麼此時如果 需要生產 號零件,那麼 需要向 提供 號零件,而此時意味着 要生產 號零件,那就需要 向 提供 號零件…
整體的提供如下:其中 表示原材料
其實這個提供材料的過程是一個遞歸的過程
那麼這道題的難點也就在這裏了,我們需要多畫圖來觀察這個遞歸關係,畫圖以後可以發現
當 號工人想生產偶數階段的零件時,軒軒需要提供奇數階段的零件
而如果 號工人軒軒需要偶數階段的零件,那麼 號工人需要提供奇數階段的零件
把這個結論拓展開來可以發現
假設 號工人需要生產 階段的零件
那麼只要 之間存在一條長度 並且和 的奇偶性相同的路徑,
號工人就必鬚生產原材料
只要確定了這件事情,之後的問題就是:我們需要求出 到所有點的距離中,奇數長度的最短路和偶數長度的最短路
之所以求最短路,其實也很好理解,因爲我們要保證 那當然求最小的了
那麼現在的問題就是如何求最短路,個人認爲這些數據點的區分就區分在瞭如何求最短路上…
那麼這裏有一個非常有趣而且簡潔的做法——拆點
我們可以把一個點拆成奇偶兩個點,也就是把 拆分成 和 兩條邊
對於新圖我們需要求的就是:
所有從 走向 的路徑,對應在原圖中就是一條 爲偶數的路徑。
所有從 走向 的路徑,對應在原圖中就是一條 爲奇數的路徑。
對於每次查詢的 和
我們只需要做如下判斷
是偶數:則只要
是奇數:則只要
#include <bits/stdc++.h>
using namespace std;
# define N 100005
# define M 200005
int n, m, query;
int head[N],ver[M],Next[M],tot=-1;
int dist[N][2];
queue<pair<int ,int> > Q;
void ADD(int x,int y){
ver[++tot] = y;
Next[tot] = head[x];
head[x] = tot;
}
void bfs(){
int x, y, t;
memset(dist, 0x3f, sizeof(dist));
Q.push(make_pair(1,0));
dist[1][0] = 0;
while (Q.size()){
int x = Q.front().first;
int t = Q.front().second;
Q.pop();
for (int i = head[x]; ~i; i = Next[i]){
y = ver[i];
if (dist[y][t ^ 1] > dist[x][t] + 1){
dist[y][t ^ 1] = dist[x][t] + 1;
Q.push(make_pair(y, t ^ 1));
}
}
}
}
int main(){
int x, y;
scanf("%d%d%d", &n, &m, &query);
memset(head, -1, sizeof(head));
for (int i = 0; i < m; i++){
scanf("%d%d", &x, &y);
ADD(x, y);
ADD(y, x);
}
bfs();
while (query--){
int A, B;
scanf("%d%d", &A, &B);
if (dist[A][B & 1] <= B){
puts("Yes");
} else {
puts("No");
}
}
return 0;
}