Test Message

c381: 聖經密碼

內容

1980 年代,以色列希伯來大學的數學家 Eliyahu Rips 和物理學家 Doron Witstum 利用電腦高速計算對比 (一套精密的數學運算模式),挑選聖經時代以來的 32 位知名人物,結果發現他們的名字和出生與死亡日期在《創世記》中都是編在一起的。後來他們把整本希伯來文聖經原文去除了所有字間距,連貫成總長 304805 個字 (因為根據傳說,摩西從上帝手中接受的聖經就是「字字相連,無一中斷」),採用電腦跳躍碼方式,在字串中尋找名字、單詞和詞組,最終找到了一系列相關信息。

現在,你也拿到了另一個不知名的古文獻,其中含有 n 個單字,你的任務是要把文中的文字「字字相連」,再依電腦所提供的 m 個整數 A1, A2, …, Am,從這個長字串找出第 A1, A2, …, Am 個字母併成一個單字。

例如
所收到的文獻為:the quick brown fox jumps over the lazy dog
連接成一個長字串:thequickbrownfoxjumpsoverthelazydog
電腦提供的線索為:33, 11, 34, 19, 21, 33, 30, 32
所併成的單字:doomsday


輸入

輸入檔中有多組測試資料。

每組測試資料的第一行是兩個正整數 n(<1000001), m(<101)。接下來的 n 行每行有一個英文單字,每個單字的長度不超過 100。最後一行有 m 個以空白隔開的正整數,所提供的數字不會超過字串的總長度。

當 n, m 均為 0 表示檔案結束,不須處理這組輸入。

9 8
the
quick
brown
fox
jumps
over
the
lazy
dog
33 11 34 19 21 33 30 32
0 0

輸出

對於每組測試資料,請輸出所擷取的文字於一行。

doomsday


解題思路

簡單的字串串接,因為資料龐大所以用一指標指向輸入位址,用 gets() 讀取輸入,再用 strlen() 取得該次輸入長度,將原指標和其相加即為下次輸入位置。

輸入完後查表輸出即可。

注意! Visual Studio 等較新的編譯器會將 gets() 讀入字串時會將'\n'字元保留,但 ZeroJudge 不會。


完整程式碼

AC (13ms, 4.9MB)
#include <stdio.h>
#include <string.h>

char list[60000010], ans[101], * input;

int main()
{
int n, m, tmp;
while (scanf(" %d %d", &n, &m) == 2 && n + m)
{
getchar();
input = list;
int length = 0;
for (int i = 0; i < n; i++)
{
gets(input);
input += strlen(input);
}
for (int i = 0; i < m; i++)
{
scanf(" %d", &tmp);
ans[i] = list[tmp - 1];
}
ans[m] = 0;
puts(ans);
}
return 0;
}

c379: 成為出題者

內容

在 Zerojudge 中,要成為出題者的條件之一是:至少答對 30%的題目。

現在 Zerojudge 上面有 x 題(x 保證是 10 的倍數),請問至少要答對幾題,才能成為出題者?


輸入

輸入只有一行,一個正整數 x(0 < x < 2000)

100

輸出

輸出答案,已經在題目敘述中敘述

30


解題思路

簡單的四則運算。


完整程式碼

AC (2ms, 104KB)
#include <stdio.h>

int main()
{
int x;
scanf(" %d", &x);
printf("%d", x * 3 / 10);
return 0;
}

c356: Justin 愛加密

內容

2018 年  4 月 1 日成功高中大門突然多了一顆石頭,但這次並不是學校出錢所買,而是從遙遠的火星飛來的神秘石頭。神秘的石頭上也寫了一串文字:

『 HDNOWEEIOWWELWDDWWLOPODWO 』,NASA 也不知道其中的含義。Justin 精通各種加密技巧,看一眼就知道其中真正的含義,也就是 『HELLO』。

只要經過 T ( 5 ) 的排列,再將對角線的字即為原文~

HDNOW

EEIOW

WELWD

DWWLO

PODWO

就成了 ->『 HELLO 』。

所以 N 也能代表秘文長度,現在給你一串原本字串及 N ,請你輸出其中真正想表達的字串。

記憶體只有 16 MB !


輸入

單筆輸入

第一行有一個整數 N 代表秘文長度 (1 <= N <= 5000)

第二行一個字串,代表石頭上出現的文字 ,長度為 N * N 。

5
HDNOWEEIOWWELWDDWWLOPODWO

輸出

輸出只有一行。

請輸出真正想表達的字串。

( 必為英文字母 A ~ Z )

HELLO


解題思路

觀察密碼字元的出現頻率,會發現他是每隔 n 個字就會出現一次,所以每次讀取資料時都讀 n+1 個字元,這時候毒入的字串首個字元即為密碼字元,將他們收集起來輸出即可。

注意!C 在讀入字串後都會在字串的後面加上'\0'表示字串結束,所以每次讀入時需用 n+2 的大小保留空位給'\0'。


完整程式碼

AC (11ms, 112KB)
#include <stdio.h>
#define MAX 5005

char s[MAX], ans[MAX];

int main()
{
int n, np;
scanf(" %d", &n);
getchar();
np = n + 2;
for (int i = 0; i < n; i++)
{
fgets(s, np, stdin);
ans[i] = s[0];
}
ans[n] = 0;
puts(ans);
return 0;
}

c350: “綠白黃” 四校聯課

內容

~大家期待已久,史無前例的四校聯課終於展開~

由沉澱主辦的四校聯課
邀請了 “ 綠綠 ” “ 白白 ” “ 黃黃 ” 三間友校一同參與
而在最後一天,三間友校為了表達謝意
將她們的電話送給沉澱的學長們~~

但事情沒有學長想像中的簡單~~他們只將其中 N 個人的電話給了學長,並開出了以下條件:smilelaughing

1. 每 K 個電話可以要其他 W 個學姊/妹的電話
2. 用過的電話不可再使用
3. 換到的電話視為新的電話(也就是可以再拿去換)

輸入

單筆輸入
輸入只有三個整數 N, K, W (N, K, W <= 10^4, 且 W < K)
代表一開始學長拿到的電話數及學姊給的限制 K 及 W

// Example 1
6 5 1

// Example 2
144 188 87

// Example 3
9 3 2

輸出

輸出只有一行一個整數。
代表學長總共可以拿到的電話總數。
答案範圍保證在 int 範圍。

// Example 1
7

// Example 2
144

// Example 3
23


解題思路

每將 k 個可用的電話號碼拿去交換,可用的電話號碼會減 k 個,能用的加 w 個,根據題意 k > w,所以可以看成每交換一次,能用的電話號碼會減少 (k-w) 個。

利用除法判斷剩下的電話號碼(n)有幾組 k 能交換,然後一次減掉 (k-w) * 組數,如此循環直到 n / k = 0 代表無法再交換了,跳出迴圈輸出答案。


完整程式碼

AC (2ms, 112KB)
#include <stdio.h>

int main()
{
int n, k, w, m, sum, gap;
scanf(" %d %d %d", &n, &k, &w);
sum = n, gap = k - w;
for (int i = n / k; i; i = n / k)
sum += w * i, n -= gap * i;
printf("%d\n", sum);
return 0;
}

c318: rilak的期末考 前傳

內容

rilak 正在準備期末考,他只有 T 單位的時間,但卻有 N 個章節要讀,每個章節讀一遍要花 1 單位的時間。

已知 rilak 讀每個章節可以讓他在考試中獲得的分數不同。

另外,同一個章節每多讀一遍,可以獲得的分數都會比上一遍還少。

假設第 i 個章節,rilak 讀第一遍可以獲得 Si 的分數,之後每一遍都會比上一遍少 Di 的分數

舉例來說,Si = 7, Di=3,第一到三遍依序可以獲得 7 分、 4 分、1 分,接下來無論讀幾遍都不會獲得分數(增加 0 分)

rilak 想知道他最多可以獲得多少分?


輸入

第一行有兩個數 N T,N 代表章節數,T 代表有多少單位的時間。

接下來 N 行,每行都有兩個數 Si Di

Si 代表第 i 個章節讀第一遍可以獲得的分數,

Di 代表第 i 個章節多讀一遍比上一遍少得多少分。

對於 100%的測資,保證

1<=N<=1000

1<=T<=1000

1<=Si<=500

1<=Di<=100

2 4
10 5
7 3

輸出

輸出一個整數,表示 rilak 最高可以獲得多少分。

26


解題思路

每次都取最大值,加進總分後將最大值遞減,如此循環直到時間歸 0。

標準的 heap sort 題,不過由於測資薄弱,就算每次都遍歷整個陣列找最大值也能輕鬆過就是了。


完整程式碼

AC (2ms, 108KB)
#include <stdio.h>
#define SWAP(x, y) (x)^=((y)^=((x)^=(y)))

typedef struct Node
{
int score, dec;
} Node;

Node heap[1010];

int last, now, base, derived;

void swapNode(int lhs, int rhs)
{
SWAP(heap[lhs].score, heap[rhs].score), SWAP(heap[lhs].dec, heap[rhs].dec);
}

void insNode()
{
last++;
scanf(" %d %d", &heap[last].score, &heap[last].dec);
now = last, base = now >> 1;
while (base && heap[now].score > heap[base].score)
swapNode(now, base), now >>= 1, base >>= 1;
}

void heapify()
{
now = 1, derived = 2;
while (derived <= last)
{
if (heap[derived].score < heap[derived + 1].score && derived < last)
derived++;
if (heap[derived].score < heap[now].score)
break;
swapNode(now, derived), now = derived, derived <<= 1;
}
}

int main()
{
int n, t, ans;
while (scanf(" %d %d", &n, &t) == 2)
{
ans = last = 0;
while (n--)
insNode();
while (t--)
{
ans += heap[1].score;
heap[1].score -= heap[1].dec;
heapify();
if (last && heap[last].score <= 0)
last--;
}
printf("%d\n", ans);
}
return 0;
}

c317: 硬幣問題!前傳

內容

小明買了 X 元的商品,要付錢發現他只有兩種硬幣,幣值分別為 a 元和 b 元。

他希望用最少的硬幣湊到「剛好」X 元,請告訴小明最少需要用多少硬幣。


輸入

第一行有一個整數 N (N <= 1,000),表示接下來會有 N 筆輸入

接下來 N 行,每一行有三個整數 X, a, b 表示小明要用 a, b 兩種幣值的硬幣湊出 X 元

(1000>= X >= a >= b >= 1)

3
258 24 20
144 11 3
309 24 9

輸出

如果可以剛好湊到 X 元,請輸出最少需要的硬幣數量。

如果沒辦法剛好湊到,請輸出 -1。

-1
16
16


解題思路

由於硬幣只有兩種,故若能形成目標值,額度較大的硬幣數越多,則需要用到的硬幣就越少。

因題目規定 a >= b,所以先找到 a 硬幣最多需要幾個才會超過目標值(x),之後迴圈用 a 去遞 x 並將其用 b 試除,若餘 0 代表可用這兩種硬幣達成目標值,再加上上面的規則,因此該組合即為答案,輸出該組合的硬幣數即可。


完整程式碼

AC (2ms, 104KB)
#include <stdio.h>

int main()
{
int n, target, coin1, coin2, i, sum, count;
while (scanf(" %d", &n) == 1)
{
while (n--)
{
scanf(" %d %d %d", &target, &coin1, &coin2);
i = target / coin1, count = -1;
sum = coin1 * (i + 1);
for (; i >= 0; i--)
{
sum -= coin1;
if ((target - sum) % coin2 == 0)
{
count = i + (target - sum) / coin2;
break;
}
}
printf("%d\n", count);
}
}
return 0;
}

c316: 最遠點對!前傳

內容

在平面上有 N 個點,編號為 0~N-1,現在給你每個點的位置 (x, y)

請找出平面上哪兩個點間的距離最遠。


輸入

第一行有一個正整數 N,表示有平面上有 N 個點。

接下來 N 行每行有兩個整數 x y ,依序代表第 0 ~ N-1 個點的座標。

(1 <= N <= 1000)

(-1000 <= x, y <= 1000)

3
0 0
3 4
5 12

輸出

輸出兩個整數 i j ,中間用空白分隔,表示第 i 個點和第 j 個點離最遠 ( i < j )。

如果算出有最遠距離的點對有很多組,請輸出 i 最小的組,如果 i 一樣,則請輸出 j 最小的組。

舉例來說,假設平面上兩點間最遠的距離為 2,且第 5 個點和第 2 個點的距離為 2,第 3 個點和第 6 個點的距離亦為 2,則輸出「2 5」。

0 2


解題思路

簡單的迴圈 + 條件判斷。

一個小細節是由於 a 到 b 的距離 = b 到 a 的距離,所以計算時可以避開會重複計算到的區域。


完整程式碼

AC (5ms, 152KB)
#include <stdio.h>
#include <math.h>

typedef struct Point
{
int X, Y;
}Point;

Point list[1010], ans;

int main()
{
double best, tmp;
int n;
while (scanf(" %d", &n) == 1)
{
best = 0;
for (int i = 0; i < n; i++)
{
scanf(" %d %d", &list[i].X, &list[i].Y);
for (int j = 0; j < i; j++)
{
tmp = sqrt((list[i].X - list[j].X) * (list[i].X - list[j].X) + (list[i].Y - list[j].Y) * (list[i].Y - list[j].Y));
if (best < tmp)
{
best = tmp;
ans.X = j;
ans.Y = i;
}
}
}
printf("%d %d\n", ans.X, ans.Y);
}
return 0;
}

c315: I, ROBOT 前傳

內容

小明有一台機器人,藉由對機器人下達指令,小明可以控制機器人的移動。

機器人一開始在原點(x=0, y=0)的位置。

下達了很多個指令後,小明卻找不到他的機器人最後移動到哪一格,他把所有下過的指令都給你,請你幫他計算機器人最後移動到了哪一格?

機器人的指令由兩個數字 a b 組成, a 代表移動的方向,b 代表移動的格子數。

a = 0 時表示往 y 正方向移動

a = 1 時表示往 x 正方向移動

a = 2 時表示往 y 負方向移動

a = 3 時表示往 x 負方向移動

舉例如下:a=2 b=3 時代表往 y 的負方向移動 3 格。

img1


輸入

第 1 行有一個數字 N,表示小明下過的指令數。

接下來 N 行,依序為機器人收到的指令,每行有兩個數字 a b。

(0 <= a <= 3)

(b >= 0)

4
0 10
1 4
2 3
3 6

輸出

請輸出兩個整數,x y,中間用一個空格分隔。

表示機器人最後停的位置。

-2 7


解題思路

簡單的條件判斷。


完整程式碼

AC (2ms, 108KB)
#include <stdio.h>

int main()
{
int n, x, y, a, b;
while (scanf(" %d", &n) == 1)
{
x = y = 0;
for (int i = 0; i < n; i++)
{
scanf(" %d %d", &a, &b);
switch (a)
{
case 0:
y += b;
break;
case 1:
x += b;
break;
case 2:
y -= b;
break;
default:
x -= b;
break;
}
}
printf("%d %d\n", x, y);
}
return 0;
}

c276: 沒有手機的下課時間

內容

文文上廁所時不小心把手機掉進馬桶裡了,所以現在下課時間他就沒辦法玩「傳說對決」,於是他就到處找人玩 xAxB 的遊戲。

在這個遊戲中,你要在心理想一個四位數數字讓對手去猜,每一位數都不可以重覆,例如 2343 裡有兩個 3,就是個不合法的數字。每次對手猜測你的數字時,你要根據對手的猜測給予提示。如果對手的四位數中有若干位數和你的答案相同,而且在正確的位置上,我們稱這些位數為 A。例如你的答案為 1536,對方猜 1234,那麼 1 和 3 就是 A。但是如果數字相同,位置不同,我們稱這些位數為 B。例如你的答案為 1536,對手猜 2345,那麼 3 和 5 就是 B。當然對手的猜測很有可能同時有 A 也有 B,例如你的答案是 1536,對手的猜測為 3456,那麼你應該給對手的提示就是 1A2B。如果所得到的提示是 4A0B,就代表完全答對!

給你文文心裡所想的四位數數字及對手所猜的數字,請你幫文文算算看要給對手什麼提示。


輸入

輸入的第一行有一個四位數的整數,代表文文心中所想的數字。

第二行有一個整數 n (n ≤ 1000),代表對手猜測的次數,接下來有 n 行,每行有一個四位數整數,代表對方的猜測。

1536
5
1234
2345
3456
2480
1536

輸出

對於對手的每一次猜測,請輸出 xAxB 的提示於一行。

2A0B
0A2B
1A2B
0A0B
4A0B


解題思路

a291 一樣的題目,只是輸入方式改變而已,就不再寫一次題解了,有需要請自行前往。


完整程式碼

AC (2ms, 92KB)
#include <stdio.h>

int main()
{
int n;
char ans[5], test[5];
while (scanf(" %s %d", ans, &n) == 2)
{
for (int i = 0; i < 4; i++)
ans[i] -= '0';
while (n--)
{
char ansCount[10] = { 0 }, testCount[10] = { 0 }, a = 0, b = 0;
scanf(" %s", test);
for (int i = 0; i < 4; i++)
test[i] -= '0';
for (int i = 0; i < 4; i++)
{
if (test[i] == ans[i])
a++;
else
{
if (ansCount[test[i]])
b++, ansCount[test[i]]--;
else
testCount[test[i]]++;
//
if (testCount[ans[i]])
b++, testCount[ans[i]]--;
else
ansCount[ans[i]]++;
}
}
printf("%dA%dB\n", a, b);
}
}
return 0;
}

c269: 裴裴與女生們

內容

裴裴剛上大學,決定來認識一些女生。校園裡有 n 個女生,分別編號為 1~n,她們都有一個共同的特性,就是如果你花 si的時間陪伴她,她就會滿足,你就會從她身上得到 vi的好感度,但花超過 si的時間陪她也不會得到額外的好感度。

但是經過裴裴的精心研究發現,這些女生可以細分為兩種類型。第一種類型的女生有一個特性,就是她們回饋你的好感度正比於你陪他們的時間。也就是如果第 i 個女生是第一類的女生,你花 si/k 的時間陪她,就會得到 vi/k 的好感度。第二種類型的女生就比較麻煩了,除非你讓他滿足(也就是花 si的時間陪她),不然你是不會得到任何好感度的。裴裴很忙,他只有 T 單位的時間可以拿來陪女生,請算出裴裴最多可以得到多少好感度?為了方便輸出,請自動將答案四捨五入至整數位。

例如:

有 4 個女生資料分別為下,且裴裴有 10 單位的時間

編號 1:s1=5,v1=15,第二類

編號 2:s2=5,v2=14,第二類

編號 3:s3=4,v1=13,第二類

編號 4:s4=8,v2=17,第二類

裴裴的最佳策略是花 5 單位的時間陪伴編號 1 的女生以及 5 單位的時間陪伴編號 2 的女生,如此可得到最多的好感度 15+14=29.

若編號 4 的女生改為第一類,則最佳策略是花 5 單位的時間陪伴編號 1 的女生,4 單位的時間陪伴編號 3 的女生,以及 1 單位的時間陪伴編號 4 的女生,如此可得到最多的好感度 15+13+17/8=30.125.(四捨五入後為 30)


輸入

測資的第一行有兩個整數 n,T 分別代表有幾個女生以及裴裴有多少單位的時間。接下來 n 行中每行有 3 個數字 si,vi,pi描述這個女生。如果裴裴花 si的時間陪伴她,她就會滿足,裴裴就會從她身上得到 vi的好感度,且這個女生是屬於第 pi類的女生。

(1≦n≦10000,1≦T,si≦1000,1≦vi≦109,pi=1 或 2)

//sample output 1
29
//sample output 2
30

輸出

對於每一筆測資,請輸出一個數字代表裴裴能獲得的最大好感度。輸出的數字請四捨五入到整數。

//sample input 1
4 10
5 15 2
5 14 2
4 13 2
8 17 2
//sample input 2
4 10
5 15 2
5 14 2
4 13 2
8 17 1


解題思路

背包問題的變種,如果只看第二類女生其實就是單純的背包問題。

而既然已經知道第二類女生的解決方案,那就想辦法將第一類女生轉換成第二類來計算。

已經知道第一類女生即使只陪她一單位時間也能拿到對應比例的好感度,那把該女生切成 n 個 1 單位時間來計算結果也會是一樣的,如此一來,第一類女生時間為 s、好感度為 v,就能將她看做

s 個 "si = 1 , vi = v/s , p = 2"的女生

Ex: "si = 5 , vi = 10 , p = 1" 就可以看作 5 個 "si = 1 , vi = 2 , p = 2" 的女生。
可以把第一類女生轉化成第二類之後,剩下就是經典的背包問題了。

注意!第一類女生轉第二類女生時好感度會用到除法且不保證整除。


完整程式碼

AC (20ms, 112KB)
#include <stdio.h>

unsigned long long favor[1010];

int main()
{
unsigned long long gFavor;
int girls, times, gTime, gType;
char flag;
scanf(" %d %d", &girls, &times);
for (int h = 0; h < girls; h++)
{
scanf("%d %llu %d", &gTime, &gFavor, &gType);
gFavor *= 100000;
if (gType == 1)
{
gFavor = gFavor / gTime;
do
{
flag = 0;
for (int i = times; i >= 1; i--)
{
if (favor[i - 1] + gFavor > favor[i])
{
favor[i] = favor[i - 1] + gFavor;
flag = 1;
}
}
} while (--gTime && flag);
}
else
{
for (int i = times; i >= gTime; i--)
{
if (favor[i - gTime] + gFavor > favor[i])
favor[i] = favor[i - gTime] + gFavor;
}
}
}
printf("%llu\n", (favor[times] + 50000) / 100000);
return 0;
}
1141516171827