Timus 1567. SMS-spam 要求计算手机短信的收费情况。
Time Limit: 1.0 second
Memory Limit: 64 MB
Petr, a student, decided to start his own business. He offers SMS advertising services to the business owners renting offices in the newly built “Prisma” tower. If an office owner wants to use the service, he devises a slogan and Petr texts it from his personal phone to thousands of Ekaterinburg citizens (he already bought the pirated list of mobile phone numbers). The cost of each slogan sent is a sum of costs of each character typed. Cost of an individual character is determined according to a very simple scheme: each tap at the phone's keyboard costs 1 rouble.
Petr's phone doesn't support sophisticated text input technologies, such as T9, and only the english alphabet can be used.
1 abc |
2 def |
3 ghi |
4 jkl |
5 mno |
6 pqr |
7 stu |
8 vwx |
9 yz |
0 .,! |
# _ |
The “_
” character in the table denotes whitespace. If you want to, for example, type “a
”, you need to press the “1
” button once. To type “k
”, you press “4
” twice. To type “!
”, press “0
” three times.
Petr has to apply this simple algorithm to calculate the cost of every slogan he sends. However, Petr is a very busy man (and, as a matter of fact, doesn't bother to learn arithmetics, because he's a Philosophy student). You just have to help Petr, you are his best friend after all.
The single line of input contains the slogan. Slogan consists of words, spaces, commas, full stops and exclamation marks. All the words consist of lowercase english letters. Slogan can't be longer than 1000 characters.
Output a single number representing the cost of the given slogan, according to Petr's pricing.
input | output |
---|---|
pokupaite gvozdi tolko v kompanii gvozdederov i tovarischi! | 114 |
Problem Author: Denis Musin
Problem Source: The XIIth USU Programing Championship, October 6, 2007
这道题目是讲俄罗斯一位学生 Petr 的创业故事。Petr 购买了数千个叶卡特琳堡市民的手机号码,以便提供发送垃圾短信服务(想不到俄罗斯也有出售非法的手机号码清单,也有垃圾短信)。Petr 是通过他的手机来发送短信的,按照他的手机键盘(跟我们常见的手机键盘的布局有些不同),“a”需要按“1”键一次,“k”需要按“4”键两次,“!”需要按“0”键三次。Petr 是按照按键次数来收费的,每一次按键收费一卢布。我们的任务就是写一个程序计算每条短信应该收多少钱。
下面是 C# 源程序:
01: using System; 02: using System.Collections.Generic; 03: 04: namespace Skyiv.Ben.Timus 05: { 06: // http://acm.timus.ru/problem.aspx?space=1&num=1567 07: sealed class T1567 08: { 09: static void Main() 10: { 11: var dict = GetPrice(); 12: var sum = 0; 13: foreach (var c in Console.ReadLine()) sum += dict[c]; 14: Console.WriteLine(sum); 15: } 16: 17: static Dictionary<char, int> GetPrice() 18: { 19: var dict = new Dictionary<char, int>(); 20: for (var i = 0; i < 4; i++) dict.Add(".,! "[i], (i % 3) + 1); 21: for (var i = 0; i < 26; i++) dict.Add((char)(i + 'a'), (i % 3) + 1); 22: return dict; 23: } 24: } 25: }
上述程序首先构造一个不同字符的收费表,然后再计算该收的费用。注意如果输入中出现了不在收费表的字符,该程序将抛出 KeyNotFoundException。但这是ACM题,我们只要按照题意写程序就行,也就是按照契约编程,不用考虑意外的输入。
下面是 C 源程序:
01: // http://acm.timus.ru/problem.aspx?space=1&num=1567 02: 03: #include <stdio.h> 04: 05: int getPrice(char c) 06: { 07: if (c == '.' || c == ' ') return 1; 08: if (c == ',') return 2; 09: if (c == '!') return 3; 10: return 1 + (c - 'a') % 3; 11: } 12: 13: int main() 14: { 15: int i, sum = 0; 16: char buf[1001]; 17: gets(buf); 18: for (i = strlen(buf) - 1; i >= 0; i--) 19: sum += getPrice(buf[i]); 20: printf("%d\n", sum); 21: return 0; 22: }
上述程序中的 getPrice 函数用来计算每个字符的收费。注意上述程序中的 gets 函数是不安全的,如果输入超出 1000 个字符,将造成缓冲区溢出。同样由于这是 ACM 题,所以不用担心。
下面是 C++ 源程序:
01: // http://acm.timus.ru/problem.aspx?space=1&num=1567 02: 03: #include <iostream> 04: #include <string> 05: 06: using namespace std; 07: 08: int getPrice(char c) 09: { 10: if (c == '.' || c == ' ') return 1; 11: if (c == ',') return 2; 12: if (c == '!') return 3; 13: return 1 + (c - 'a') % 3; 14: } 15: 16: int main() 17: { 18: string buf; 19: getline(cin, buf); 20: int sum = 0; 21: for (string::iterator it = buf.begin(); it < buf.end(); it++) 22: sum += getPrice(*it); 23: cout << sum << endl; 24: return 0; 25: }
上述程序和 C 程序基本上是一样的,不过 getline 函数是安全的。
下面是 F# 源程序:
01: // http://acm.timus.ru/problem.aspx?space=1&num=1567 02: 03: let getPrice c = 04: match c with 05: | '.' | ' ' -> 1 06: | ',' -> 2 07: | '!' -> 3 08: | x -> 1 + (int x - int 'a') % 3 09: 10: let pricing str = str |> Seq.map getPrice |> Seq.sum 11: 12: System.Console.ReadLine() |> pricing |> printfn "%d"
可以看出 F# 程序最简单明了,Seq.map 根据 getPrice 来计算每个字符的收费,再用 Seq.sum 来求和。