Four Case-Insensitive Word Tests
National Olympiad — Regional round (2011 season)
Submission name: letters.cpp
Problem summary
For n rows of four words and one target letter, count: column 1 words starting with it, column 2 words containing it, column 3 words containing it at least twice, and column 4 words ending with it. Ignore letter case.
Input
n and a lowercase Latin letter, followed by n rows of four Latin-letter words.
Output
Four counts in the specified column order.
Constraints
1 < n < 10000; each word has at most 50 characters.
Worked example
Input and output for the worked example discussed below.
Input
3 a Ani Miraj Masa Bala Taralej toto Dani Kana ananas pile ananas Tapa
Output
2 1 2 3
Solution analysis
- Process each column according to its own predicate. Convert every word to lowercase first, so uppercase A and lowercase a are treated identically.
- For columns 1 and 4 inspect the first or last character. For columns 2 and 3 count occurrences, then compare the count with 1 or 2. Increment the result once per qualifying word, not once per matching character.
- In the example, Ani and ananas start with a; only Miraj in column 2 contains a; Masa and ananas in column 3 have at least two; all three column-4 words end in a. The output is 2 1 2 3.
Why it works
Lowercasing preserves exactly case-insensitive equality. Each word is checked against its column’s stated condition, and contributes one if and only if that condition holds. Summing these indicators gives the four required word counts.
Watch out. Do not count individual occurrences as words. Apply the predicates to their proper columns. Cast to unsigned char before tolower to avoid undefined behavior for negative char values.
Commented C++17 solution
An independently written complete program with standard headers.
#include<algorithm>
#include<cctype>
#include<iostream>
#include<string>
using namespace std;
int main(){
int n;
char target;
cin>>n>>target;
int answer[4]={};
for(int row=0;row<n;row++){
for(int column=0;column<4;column++){
string word;
cin>>word;
for(char&letter:word){
letter=char(tolower(static_cast<unsigned char>(letter)));
}
int occurrences=count(word.begin(),word.end(),target);
// Each column tests a word once, not once per matching letter.
bool valid=column==0?word.front()==target
:column==1?occurrences>=1
:column==2?occurrences>=2
:word.back()==target;
answer[column]+=valid;
}
}
cout<<answer[0]<<' '<<answer[1]<<' '<<answer[2]<<' '<<answer[3]<<'\n';
}