顯示具有 CPE 標籤的文章。 顯示所有文章
顯示具有 CPE 標籤的文章。 顯示所有文章

2022年3月7日 星期一

f447: 12918 - Lucky Thief

解題心得

這題滿簡單的,想不到會在第四題。

只要稍微推一下就知道是連續數字的相加,代入公式就好,但沒想到CPE測資比ZJ嚴格。

程式碼

#include <iostream>
using namespace std;

int main()
{
	long long int t, n, m;
	cin >> t;
	while (t--)
	{
		cin >> n >> m;
		cout << (m - 1 + m - n) * n / 2 << endl;
	}
	return 0;
}

f446: 1237 - Expert Enough

解題心得

每次有新的query,就掃過所有車種,看有幾個符合,以及記錄符合的index。

如果有零個或不只一個,那就不對。如果只有一個,那就可以用index找到車種名稱了。

程式碼

#include <iostream>
#include <string>
using namespace std;

struct carInfo
{
	string name;
	int low, high;
};
carInfo db[10000];
int main()
{
	int t, d, l, h, q, p;
	string m;
	cin >> t;
	while (t--)
	{
		cin >> d;

		for (int i = 0; i < d; i++)
			cin >> db[i].name >> db[i].low >> db[i].high;
		cin >> q;
		while (q--)
		{
			cin >> p;
			int flag = 0, index = -1;
			for (int i = 0; i < d; i++)
			{
				if (db[i].low <= p && p <= db[i].high)
					flag++, index = i;
			}
			if (flag != 1) cout << "UNDETERMINED" << endl;
			else cout << db[index].name << endl;
		}
		
		if (t != 0) cout << endl;
	}
	return 0;
}

f445: 263 - Number Chains

解題心得

照著題目敘述做就好。

程式碼

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int descending(int n)
{
	int arr[10] = { 0 }, ans = 0;
	while (n)
	{
		arr[n % 10]++;
		n /= 10;
	}
	for (int i = 9; i >= 0; i--)
	{
		while (arr[i] != 0)
		{
			ans = ans * 10 + i;
			arr[i]--;
		}
	}
	return ans;
}
int ascending(int n)
{
	int arr[10] = { 0 }, ans = 0;
	while (n)
	{
		arr[n % 10]++;
		n /= 10;
	}
	for (int i = 0; i < 10; i++)
	{
		while (arr[i] != 0)
		{
			ans = ans * 10 + i;
			arr[i]--;
		}
	}
	return ans;
}
int main()
{
	int n;
	while (cin >> n && n)
	{
		vector<int> v;
		cout << "Original number was " << n << endl;
		while (true)
		{
			int ascend = ascending(n), descend = descending(n), result = descend - ascend;
			cout << descend << " - " << ascend << " = " << result << endl;
			
			if (v.size() != 0 && find(v.begin(), v.end(), result) != v.end())
				break;
			v.push_back(result);
			n = result;
		}
		cout << "Chain length " << v.size() + 1 << endl << endl;
		
	}
	return 0;
}

f444: 10268 - 498-bis

解題心得

CPE 的系統跟 zerojudge 的測資格式不太一樣,後者好像不是用 \n 換行,只好再用別的方法寫。

程式碼

[for CPE]

#include <iostream>
#include <vector>
#include <math.h>
using namespace std;

int main()
{
	long long int x, a;
	while (cin >> x)
	{
		vector<long long int> bits;
		long long int ans = 0;
		while (cin >> a && getchar() != '\n')
			bits.push_back(a);
		for (int i = 0; i < bits.size(); i++)
		{
			bits[i] *= bits.size() - i;
			ans += bits[i] * pow(x, bits.size() - 1 - i);
		}
		cout << ans << endl;
	}
	return 0;
}

[for ZJ]

#include <iostream>
#include <vector>
#include <sstream>
#include <math.h>
#include <string>
using namespace std;

int main()
{
	long long int x, a;
	string s;
	while (cin >> x)
	{
		vector<long long int> bits;
		long long int ans = 0;
		cin.ignore();
		getline(cin, s);
		stringstream ss(s);
		while (ss >> a)
			bits.push_back(a);
		bits.pop_back();
		for (int i = 0; i < bits.size(); i++)
		{
			bits[i] *= bits.size() - i;
			ans += bits[i] * pow(x, bits.size() - 1 - i);
		}
		cout << ans << endl;
	}
	return 0;
}

2022年3月6日 星期日

f439: 10191 - Longest Nap

解題心得

這題不難,只是很多瑣碎的地方要弄。

基本上就是把開始跟結束時間轉換成分鐘,然後用陣列來記錄哪些時候有空或沒空,最後再從頭掃到尾找最長的空檔。因為是10:00開始,把所有轉換後的時間減10*60分鐘。

寫完後覺得寫很醜,如果用開始跟結束時間作為標記,不知道會不會好看一點。

程式碼

#include <iostream>
#include <string>
using namespace std;

int t[480] = { 0 };

int to_int(string s)
{
	int n = 0;
	n = stoi(s.substr(0, 2)) * 60 + stoi(s.substr(3, 2)) - 600;
	return n;
}

int main()
{
	int testcase, counter = 1;
	while (cin >> testcase)
	{
		cin.ignore();
		for (int i = 0; i < 480; i++) t[i] = 0;
		for (int days = 1; days <= testcase; days++)
		{
			string s, start, end;
			getline(cin, s);
			start = s.substr(0, 5);
			end = s.substr(6, 5);
			for (int i = to_int(start); i <= to_int(end); i++)
				t[i] = 1;

			//cout << to_int(start) << " " << to_int(end) << endl;
		}
		int prev = -1, count = 0, maxCount = 0, curTime = 0, time = 0;
		for (int i = 0; i < 480; i++)
		{
			if (t[i] == 0)
				count++;
			if ((t[i] == 1 && prev == 0) || i == 479)
			{
				if (curTime == 0) count--;
				if (count + 1 > maxCount)
				{
					maxCount = count + 1;
					time = curTime;
				}
				count = 0;
				//cout << "update: " << maxCount << endl;
			}
			if (t[i] == 0 && prev == 1)
				curTime = i - 1;
			prev = t[i];
		}
		cout << "Day #" << counter++ << ": the longest nap starts at " << (time + 600) / 60 << ":";
		if ((time + 600) % 60 < 10) cout << "0" << (time + 600) % 60 ;
		else cout << (time + 600) % 60;
		cout << " and will last for ";
		if (maxCount < 60) cout << maxCount << " minutes.\n";
		else cout << maxCount / 60 << " hours and " << maxCount % 60 << " minutes.\n";

	}
	return 0;
}
// 18*60 - 10*60 = 8*60 = 480

2022年3月5日 星期六

f438: 855 - Lunch in Grid City

解題心得

最後好像也沒用到s跟a的值。

程式碼

#include <iostream>
#include <algorithm>
using namespace std;


int main()
{
	int t, s, a, f;
	cin >> t;
	while (t--)
	{
		int arrS[50001], arrA[50001];
		cin >> s >> a >> f;
		for (int i = 0; i < f; i++)
			cin >> arrS[i] >> arrA[i];
		sort(arrS, arrS + f);
		sort(arrA, arrA + f);

		if (f % 2 == 1) cout << "(Street: " << arrS[f / 2] << ", Avenue: " << arrA[f / 2] << ")" << endl;
		else cout << "(Street: " << arrS[f / 2 - 1] << ", Avenue: " << arrA[f / 2 - 1] << ")" << endl;
	}
	return 0;
}

f437: 1368 - DNA Consensus String

解題心得

要找到第 i 個會是哪個字母,就去統計所有的字串的第 i 個都是哪些字母,找出現最多的那個。如果出現次數相同,則按照字典序順序,所以判斷式的等於才會那樣寫。

要計算 hamming 距離,就是統計不符合的字元次數。

程式碼

#include <iostream>
using namespace std;

int main()
{
	int t, m, n;
	string s[50];
	cin >> t;
	while (t--)
	{
		cin >> m >> n;
		for (int i = 0; i < m; i++)
			cin >> s[i];
		string ans = "";
		int d = 0;
		for (int i = 0; i < n; i++)
		{
			int countA = 0, countT = 0, countC = 0, countG = 0;
			for (int j = 0; j < m; j++)
			{
				if (s[j][i] == 'A') countA++;
				else if (s[j][i] == 'T') countT++;
				else if (s[j][i] == 'C') countC++;
				else if (s[j][i] == 'G') countG++;
			}
			if (countA >= countC && countA >= countG && countA >= countT)
				ans += "A", d += countC + countG + countT;
			else if (countC > countA && countC >= countG && countC >= countT)
				ans += "C", d += countA + countG + countT;
			else if (countG > countA && countG > countC && countG >= countT)
				ans += "G", d += countC + countA + countT;
			else
				ans += "T", d += countC + countG + countA;
		}
		cout << ans << endl << d << endl;
	}
	return 0;
}

2022年3月3日 星期四

11498: Division of Nlogonia

解題心得

沒有心得。

程式碼

#include <iostream>
using namespace std;

int main()
{
	int t, n, m, x, y;
	while (cin >> t && t)
	{
		cin >> n >> m;
		while (t--)
		{
			cin >> x >> y;
			if (x > n && y > m)
				cout << "NE" << endl;
			else if (x < n && y > m)
				cout << "NO" << endl;
			else if (x > n && y < m)
				cout << "SE" << endl;
			else if (x < n && y < m)
				cout << "SO" << endl;
			else
				cout << "divisa" << endl;
		}
	}
	return 0;
}

2022年2月3日 星期四

Uva 10267: Graphical Editor

解題心得

看起來很麻煩,但基本上只要照著題目敘述做就好,最難的部分只有DFS。

程式碼

#include <iostream>
using namespace std;

char table[101][101];
int m, n;

void fill(int x, int y, char c, char currentColor)
{
	if(currentColor==c) return;
	table[y][x]=c;
	
	if(x>=2 && table[y][x-1]==currentColor) fill(x-1,y,c,currentColor);
	if(x<m && table[y][x+1]==currentColor) fill(x+1,y,c,currentColor);
	if(y>=2 && table[y-1][x]==currentColor) fill(x,y-1,c,currentColor);
	if(y<n && table[y+1][x]==currentColor) fill(x,y+1,c,currentColor);
}

int main()
{
	char cmd,c;
	int x1,x2,y1,y2;
	string name,s;
	while(cin>>cmd)
	{
		if(cmd=='I')
		{
			cin>>m>>n;
			for(int i=0;i<=n;i++)
				for(int j=0;j<=m;j++)
					table[i][j]='O';
		}
		else if(cmd=='L')
		{
			cin>>x1>>y1>>c;
			table[y1][x1]=c;
		}
		else if(cmd=='S')
		{
			cin>>name;
			cout<<name<<endl;
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=m;j++)
					cout<<table[i][j];
				cout<<endl;
			}
					
		}
		else if(cmd=='F')
		{
			cin>>x1>>y1>>c;
			fill(x1,y1,c,table[y1][x1]);
		}
		else if(cmd=='V')
		{
			cin>>x1>>y1>>y2>>c;
			if(y1>y2) swap(y1,y2);
			for(int i=y1;i<=y2;i++)
				table[i][x1]=c;
		}
		else if(cmd=='H')
		{
			cin>>x1>>x2>>y1>>c;
			if(x1>x2) swap(x1,x2);
			for(int i=x1;i<=x2;i++)
				table[y1][i]=c;
		}
		else if(cmd=='K')
		{
			cin>>x1>>y1>>x2>>y2>>c;
			for(int i=y1;i<=y2;i++)
				for(int j=x1;j<=x2;j++)
					table[i][j]=c;
		}
		else if(cmd=='C')
		{
			for(int i=0;i<101;i++)
				for(int j=0;j<101;j++)
					table[i][j]='O';
		}
		else if(cmd=='X')
			break;
		else
		{
			cin.ignore();
			getline(cin,s);
		}
	}
}

Uva 389: Basically Speaking

解題心得

先把數字轉回十進位,再轉成要求的進位制表示法。

程式碼

#include <iostream>
using namespace std;

int to_decimal(string s, int base)
{
	int ans = 0;
	for (int i = 0; i < s.size(); i++)
	{
		if ('0' <= s[i] && s[i] <= '9')
			ans = ans * base + s[i] - '0';
		else
			ans = ans * base + s[i] - 'A' + 10;
	}
	return ans;
}
string convert(int n, int base)
{
	string s = "";
	while (n > 0)
	{
		int tmp = n % base;
		if (tmp >= 10)
			s = char(tmp - 10 + 'A') + s;
		else
			s = char(tmp + '0') + s;
		n /= base;
	}
	while (s.size() < 7)
		s = "0" + s;
	while (s.size() > 7)
		s = s.erase(0, 1);
	return s;
}

int main()
{
	string origin;
	int origin_base, new_base;
	while (cin >> origin)
	{
		cin.ignore();
		cin >> origin_base >> new_base;
		int decimal = to_decimal(origin, origin_base);
		cout << convert(decimal, new_base) << endl;
	}
	return 0;
}

2022年2月2日 星期三

Uva 458: The Decoder

解題心得

CPE第二題居然比第一題簡單

程式碼

#include <iostream>
using namespace std;

int main()
{
	string s;
	while(cin>>s)
	{
		for(int i=0;i<s.size();i++)
			cout<<char(s[i]-7);
		cout<<endl;
	}
	return 0;
}

Uva 10050: Hartals

解題心得

如果先判斷日期是不是週五週六,反而會超時QQ

程式碼

#include <iostream>
using namespace std;

int main()
{
	int T,n,p,h[101]={0};
	cin>>T;
	while(T--)
	{
		int ans=0;
		cin>>n>>p;
		for(int i=0;i<p;i++)
			cin>>h[i];
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<p;j++)
			{
				if(i%h[j]==0&&i%7!=0&&i%7!=6)
				{
					ans++;
					break;
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

2022年2月1日 星期二

Uva 11960: Divisor Game

解題心得

原本的想法是用質數篩法建質數表,然後一個個用質因數分解找因數,因為一個數的因數數量就是質因數次方加一的乘積。

例:36 = 2^2 + 3^2,其因數數量為(2+1)*(2+1)=9。背後原因很簡單就不贅述。

不過寫完後發現會TLE,只好放棄。

參考了CPE提供的參考解法,發現解法其實很簡單。首先同樣要建表,這次建的是因數表。何謂因數?就是某數可以整除的數。反過來想,把某數的倍數與自己通通都加一,因為一定能整除。

為了近一步縮短時間,提前建好答案表。答案表紀錄從1~i的範圍內,因數數量最多的是誰。注意若數量相同,也要更新。

講起來很容易,但就是想不到啊。

程式碼

#include <iostream>
using namespace std;

#define SIZE 1000001

int table[SIZE] = { 0 }, ans[SIZE] = { 0 };

int main()
{
	for (int i = 1; i < SIZE; i++)
	{
		for (int j = i; j < SIZE; j += i)
			table[j]++;
	}
	int maxIndex = 1, maxCount = 0;
	for (int i = 1; i < SIZE; i++)
	{
		if (table[i] >= maxCount)
		{
			maxIndex = i;
			maxCount = table[i];
		}
		ans[i] = maxIndex;
	}
	
	int T, n;
	cin >> T;
	while (T--)
	{
		cin >> n;
		cout << ans[n] << endl;
	}
	return 0;
}

Uva 11536: Smallest Sub-Array

解題心得

參考網路解法才寫出來。

這題似乎要用到two pointer的概念的變化題。

先假設用一個queue來記錄所有sequence中1~k數字的index,以及countk紀錄當下蒐集到1~k中的總共幾個數字,跟一個array來記錄i最後出現的位置。

每次遇到1~k數字,就先丟進queue中。接著檢查是否第一次遇到這個數字(有沒有在queue中,也就是有沒有在highlight起來的範圍內),若沒有,則更新countk。最後,我們要檢查highlight範圍左側是不是要變化了,判斷方法是看範圍內的最左側,若去掉該位置,依然能保有1~k的數字,那就可以放棄,一直重覆到不能為止。

那又要怎麼確保會找到最短長度呢?首先我們知道當countk==k時就是一組解,而我們的解法是從頭到尾掃過一次並且動態更新,那麼只要每次都檢查當前的解是否更小即可。

另外我在比較cpe提供的參考解法與網路其他人解法時,一開始不懂為何countk只要++,不考慮--的情況。這是因為只有一開始才是還沒找到解的狀態,只要一找到符合的解,只會不斷解查是不是要更新邊界,但也會確保始終是保持1~k數字的區間。

程式碼 

#include <iostream>
#include <queue>
using namespace std;

int seq[1000001] = { 1,2,3 };

int main()
{
	int T;
	cin >> T;
	for (int round = 1; round <= T; round++)
	{
		int n, m, k;
		cin >> n >> m >> k;

		for (int i = 3; i < n; i++)
			seq[i] = (seq[i - 1] + seq[i - 2] + seq[i - 3]) % m + 1;

		queue<int> q;
		int countK = 0, last_pos[101] = { 0 }, ans = 1000001;
		for (int i = 0; i < 101; i++) last_pos[i] = -1;
		for (int i = 0; i < n; i++)
		{
			if (seq[i] <= k)
			{
				q.push(i);
				if (last_pos[seq[i]] == -1) countK++;
				last_pos[seq[i]] = i;

				while (q.front() != last_pos[seq[q.front()]])
					q.pop();
				if (countK == k)
					ans = min(ans, i - q.front() + 1);
			}
		}
		cout << "Case " << round << ": ";
		if (ans == 1000001) cout << "sequence nai" << endl;
		else cout << ans << endl;
	}
	return 0;
}

2022年1月29日 星期六

Uva 10415: Eb Alto Saxophone Player

解題心得

暴力解

程式碼

#include <iostream>
using namespace std;

int main()
{
	string c="0111001111", d="0111001110", e="0111001100", f="0111001000", g="0111000000",
		a="0110000000", b="0100000000", C="0010000000", D="1111001110", E="1111001100",
		F="1111001000", G="1111000000", A="1110000000", B="1100000000";
	int t;
	cin>>t;
	while(t--)
	{
		string s, now="0000000000", next;
		int count[10]={0};
		cin>>s;
		for(int i=0;i<s.size();i++)
		{
			if(s[i]=='c') next=c;
			else if(s[i]=='d') next=d;
			else if(s[i]=='e') next=e;
			else if(s[i]=='f') next=f;
			else if(s[i]=='g') next=g;
			else if(s[i]=='a') next=a;
			else if(s[i]=='b') next=b;
			else if(s[i]=='C') next=C;
			else if(s[i]=='D') next=D;
			else if(s[i]=='E') next=E;
			else if(s[i]=='F') next=F;
			else if(s[i]=='G') next=G;
			else if(s[i]=='A') next=A;
			else if(s[i]=='B') next=B;
			
			for(int i=0;i<10;i++)
			{
				if(now[i]=='0'&&next[i]=='1')
					count[i]++;
			}
			now=next;
			
		}
		
		for(int i=0;i<10;i++)
		{
			if(i!=9) cout<<count[i]<<" ";
			else cout<<count[i]<<endl;
		}
	}
	return 0;
}

2022年1月28日 星期五

Uva 10188: Automated Judge Script

解題心得

比對解答與提交答案的部分,主要是一個字元一個字元檢查。如果兩個字元都一樣,那就往下一個字元繼續看;如果其中一個是空白但另一個不是,則可能是PE,就先標記起來然後跳過空白;如果字元不一樣,而且也不是因為空白,那就是WA,可以直接跳出迴圈。

比較麻煩的是換行的部分,會造成PE誤判成AC,因為好像檢查不到「\n」。我想說這種狀況,會出現在原本被判AC,但因為換行,導致解答跟提交答案的行數不同,就從這裡判斷就好了。

程式碼

#include <iostream>
#include <string>
using namespace std;

int main()
{
	int n, m, count = 1;
	while (cin >> n)
	{
		if (n == 0) break;

		cin.ignore();
		string solution[100], team_output[100];
		int solution_len = 0;

		// read input
		for (int i = 0; i < n; i++)
		{
			getline(cin, solution[i]);
			solution_len += solution[i].size();
		}
		cin >> m;
		cin.ignore();
		for (int i = 0; i < m; i++)
			getline(cin, team_output[i]);

		// judge
		bool pe = false, wa = false;
		int i = 0, j = 0, len1 = 0, len2 = 0;
		while (i < n)
		{
			while (len1 < solution[i].size()) // && len2<team_output[i].size()
			{
				if (solution[i][len1] == team_output[j][len2])
					len1++, len2++;
				else if (solution[i][len1] == ' ' || solution[i][len1] == '\n')
				{
					len1++;
					pe = true;
				}
				else if (team_output[j][len2] == ' ' || team_output[j][len2] == '\n')
				{
					len2++;
					pe = true;
				}
				else
				{
					wa = true;
					break;
				}

				if (len2 >= team_output[j].size())
					j++, len2 = 0;
			}
			i++; len1 = 0;
		}
		cout << "Run #" << count++ << ": ";
		if (wa)
			cout << "Wrong Answer ";
		else if (pe || n!=m)
			cout << "Presentation Error ";
		else
			cout << "Accepted ";
		cout << solution_len << endl;

	}
	return 0;
}

Uva11689 Soda Surpler

解題心得

照著題目敘述寫就好了

程式碼

#include <iostream>
using namespace std;

int main()
{
	int N;
	cin>>N;
	while(N--)
	{
		int e, f, c, total=0,bottle=0;
		cin>>e>>f>>c;
		bottle = e+f;
		
		while(bottle>=c)
		{
			int tmp = bottle/c; // can buy now many soda
			bottle -= tmp*c; // use the empty bottle to buy soda
			bottle += tmp; // new empty bottle
			total += tmp; // update drink soda amount
		}
		cout<<total<<endl;
	}
	return 0;
}

2022年1月25日 星期二

UVA725

解題心得

一開始看到這題完全沒有頭緒,看了CPE提供的解說影片才有想法。

首先,用列舉的方式窮舉所有可能,如果該數字組合符合等式,再檢查數字是否重複。判斷等式成立與否也未必要用除的,用分母乘以N得到分子,這樣能縮小窮舉範圍。

思考到這裡,剩下的就是枚舉所有可能的分母,只要乘以N必定能讓等式成立,而分母的窮舉範圍其實可以進一步縮減到01234~98765。

太久沒解題,最後還卡在換行上XD

程式碼

#include <iostream>
using namespace std;

bool isValid(int a, int b)
{
	if(a>99999 || b>99999) return false;
	
	int count[10] = {0};
	if(a<10000) count[0]++;
	if(b<10000) count[0]++;
	while(a>0)
	{
		count[a%10]++;
		a/=10;
	}
	while(b>0)
	{
		count[b%10]++;
		b/=10;
	}
	for(int i=0;i<10;i++)
	{
		if(count[i]!=1)
			return false;
	}
	return true;
}

int main()
{
	int n;
	bool isFirst=true;
	
	while(cin>>n)
	{
		if(n==0) break;
		
		bool hasAns=false;
		
		if(isFirst) isFirst=false;
		else cout<<endl;
		
		for(int i=1234;i<=98765;i++)
		{
			int j = i * n;
			if(isValid(i, j))
			{
				hasAns=true;
				if(j<10000) cout<<"0"<<j<<" / ";
				else cout<<j<<" / ";
				if(i<10000) cout<<"0"<<i<<" = "<<n<<endl;
				else cout<<i<<" = "<<n<<endl;
			}
		}
		if(!hasAns) cout<<"There are no solutions for "<<n<<"."<<endl;
		
		
	}
	return 0;
}

UVA12218

解題心得
照著題目敘述做。
如果輪到誰,誰卻跳出迴圈,就代表輸了。

程式碼
#include <iostream>
using namespace std;

int sum_of_digits(string s)
{
	int sum=0;
	for(int i=0;i<s.length();i++)
		sum+=s[i]-'0';
	return sum;
}
int can_remove(string s)
{
	if(s.length()==0) return -1;
	
	int sum=sum_of_digits(s);
	for(int i=0;i<s.length();i++)
	{
		if((sum-(s[i]-'0'))%3==0)
			return i;
	}
	return -1;
}

int main()
{
	int T;
	cin>>T;
	
	for(int round=1;round<=T;round++)
	{
		bool isT=false; // s first
		string s;
		cin>>s;
		
		while(1){
			int index=can_remove(s);
			if(index==-1) break;
			s=s.erase(index,1);
			isT=!isT;
		}
		
		cout<<"Case "<<round<<": ";
		cout<< (isT ? "S" : "T") << endl;
	}
	return 0;
}

2022年1月24日 星期一

UVA10921

解題心得

照著題目敘述寫就好了。

程式碼

#include <iostream>
using namespace std;

int find_table(char c)
{
	if(c=='A' || c=='B' || c=='C') return 2;
	else if(c=='D' || c=='E' || c=='F') return 3;
	else if(c=='G' || c=='H' || c=='I') return 4;
	else if(c=='J' || c=='K' || c=='L') return 5;
	else if(c=='M' || c=='N' || c=='O') return 6;
	else if(c=='P' || c=='Q' || c=='R' || c=='S') return 7;
	else if(c=='T' || c=='U' || c=='V') return 8;
	else if(c=='W' || c=='X' || c=='Y' || c=='Z') return 9;
}
int main()
{
	string s;
	while(cin>>s)
	{
		int capital=0, hyphen=0;
		for(int i=0;i<s.length();i++)
		{
			if(s[i]=='-' || s[i]=='1' || s[i]=='0')
				cout<<s[i];
			else
				cout<<find_table(s[i]);
				
			if(s[i]=='-') hyphen++;
			if(isupper(s[i])) capital++; 
		}
		cout<<" "<<capital<<" "<<hyphen<<endl;
	}
	return 0;
}