题目描述
题目要求生成已清算支票的汇总列表。输入为按日期排序的支票交易记录,每行包含日期、支票号码和金额。输出需按支票号码升序排列,并分成三列显示。对于不连续(即不是前一个支票号码加111)的支票号码,需在其后标记星号*。输出格式要求每列之间用三个空格分隔,每列包含支票号码(可选*)、金额和日期。
输入格式
第一行一个整数NNN,表示测试用例的数量,后面跟一个空行。
接下来NNN组测试用例,每组包含若干行,每行格式为yy/mm/dd 支票号码 金额,金额可能包含前导零、缺少小数部分等不规范格式。每组测试用例之间由一个空行分隔。输入以文件结束符(EOF\texttt{EOF}EOF)终止。
输出格式
对于每组测试用例,输出三列格式的支票列表,按支票号码升序排列。每行的三个条目分别来自三列的同一行位置(即先行后列填充)。每列格式为:
nnnn* dddddd.cc yy/mm/dd其中nnnn为支票号码(无前导零),*为出序列指示符(若连续则为空格),dddddd.cc为金额(至少111位整数部分,222位小数,小于111美元时整数部分为000),yy/mm/dd为日期。列之间用三个空格分隔。每组输出后跟一个空行。
样例
输入
1 93/10/01 998 .65 93/10/01 999 123.89 93/10/05 996 29.99 93/10/06 993 116.52 93/10/12 995 418.00 93/10/15 1001 15045.00 93/10/27 1000 840.85输出
993 116.52 93/10/06 998* 0.65 93/10/01 1001 15045.00 93/10/15 995* 418.00 93/10/12 999 123.89 93/10/01 996 29.99 93/10/05 1000 840.85 93/10/27题目分析
本题的核心是处理支票数据并按照三列格式输出。需要处理以下几个子任务:
金额格式化
输入金额可能存在各种不规范格式,例如:
- 缺少整数部分的
.65 - 缺少小数部分的
123. - 整数形式无小数点的
418 - 带前导零的
0.65
需要将其规范化为dddddd.cc格式:
- 去除前导零(但保留至少一位整数,若为000则保留一个
0)。 - 若以小数点开头,添加前导
0。 - 若以小数点结尾,添加两个
0。 - 若无小数点,添加
.00。 - 若小数点后只有一位,补一个
0。 - 金额大于等于1,000,0001,000,0001,000,000的支票需要忽略(题目保证不会出现,但仍需处理)。
出序列标记
将支票按号码升序排序后,对于每个支票,检查其号码是否等于前一个支票号码+1+1+1。若不是,则在该支票号码后标记*;否则标记空格。第一张支票的号码不标记*(无前一个支票)。
三列输出
输出需要按列填充:先填第一列,再填第二列,最后填第三列。设总支票数为total\textit{total}total,行数RRR的计算方式为:
- 若total≤3\textit{total} \le 3total≤3,则R=1R = 1R=1。
- 否则,需要确定RRR使得三列尽可能均匀填充,且中间列优先填满。
具体计算方式:
- 设R=⌈total/3⌉R = \lceil \textit{total} / 3 \rceilR=⌈total/3⌉。
- 第一列(左列)通常有RRR行,但若total mod 3=1\textit{total} \bmod 3 = 1totalmod3=1,则第一列需多一行(共RRR行,但实际分布为第一列RRR行,第二列R−1R-1R−1行,第三列R−1R-1R−1行?需要根据样例推导)。
观察参考代码的实现:它采用了显式分配三列起止索引的方法,根据total mod 3\textit{total} \bmod 3totalmod3的值进行分配:- 若total mod 3=0\textit{total} \bmod 3 = 0totalmod3=0:每列total/3\textit{total} / 3total/3个元素。
- 若total mod 3=1\textit{total} \bmod 3 = 1totalmod3=1:第一列total/3+1\textit{total} / 3 + 1total/3+1,第二列total/3+1\textit{total} / 3 + 1total/3+1,第三列total/3−1\textit{total} / 3 - 1total/3−1?实际代码中计算为
total -= 4; total /= 3;然后第一列total + 2,第二列2 * total + 4,第三列末尾。这意味着当total mod 3=1\textit{total} \bmod 3 = 1totalmod3=1时,第一列和第二列各多一行。 - 若total mod 3=2\textit{total} \bmod 3 = 2totalmod3=2:第一列total/3+1\textit{total} / 3 + 1total/3+1,第二列total/3+1\textit{total} / 3 + 1total/3+1,第三列total/3\textit{total} / 3total/3。
输出格式
每行输出三个支票条目(若对应列存在)。每个条目中:
- 支票号码占555列,右对齐(包括可选的
*或空格)。 - 金额占101010列,右对齐。
- 日期后无额外空格,直接输出。
列之间用三个空格分隔。
复杂度分析
每组数据需要排序O(MlogM)O(M \log M)O(MlogM),MMM为支票数量,可接受。
代码实现
// Fifth Bank of Swamp County// UVa ID: 426// Verdict: Accepted// Submission Date: 2016-08-05// UVa Run Time: 0.000s//// 版权所有(C)2016,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;structitem{intnumber;string number_text,money,date;booloperator<(constitem&another)const{returnnumber<another.number;}};intmain(intargc,char*argv[]){cin.tie(0);cout.tie(0);ios::sync_with_stdio(false);string line,date,number,money;getline(cin,line);intcases=stoi(line);getline(cin,line);for(inti=1;i<=cases;i++){if(i>1)cout<<'\n';vector<item>checks;while(getline(cin,line),line.length()>0){money="0.00";istringstreamiss(line);iss>>date>>number>>money;// special caseswhile(money.length()>0&&money.front()=='0')money.erase(money.begin());if(money.length()==0)money+="0.00";if(money.front()=='.')money.insert(money.begin(),'0');if(money.back()=='.')money+="00";if(money.find('.')==money.npos)money+=".00";if(money[money.length()-2]=='.')money.push_back('0');if(money[money.length()-3]!='.')money.erase(money.end()-1);if(stod(money)>=1000000)continue;item data;data.number=stoi(number);data.number_text=to_string(data.number);data.money=money;data.date=date;checks.push_back(data);}sort(checks.begin(),checks.end());checks[0].number_text+=' ';for(inti=1;i<checks.size();i++)if(checks[i].number!=checks[i-1].number+1)checks[i].number_text+='*';elsechecks[i].number_text+=' ';pair<int,int>column1,column2,column3;inttotal=checks.size();if(total%3==0){total/=3;column1.first=0,column1.second=total;column2.first=total,column2.second=2*total;column3.first=2*total,column3.second=checks.size();}elseif(total%3==1){total-=4;total/=3;column1.first=0,column1.second=total+2;column2.first=total+2,column2.second=2*total+4;column3.first=2*total+4,column3.second=checks.size();}else{total-=2;total/=3;column1.first=0,column1.second=total+1;column2.first=total+1,column2.second=2*total+2;column3.first=2*total+2,column3.second=checks.size();}total=checks.size();for(inti=column1.first;i<column1.second;i++){cout<<setw(5)<<right<<checks[i].number_text;cout<<setw(10)<<right<<checks[i].money;cout<<' '<<checks[i].date;if(i+column2.first<column2.second&&i+column2.first<total){cout<<" ";cout<<setw(5)<<right<<checks[i+column2.first].number_text;cout<<setw(10)<<right<<checks[i+column2.first].money;cout<<' '<<checks[i+column2.first].date;}if(i+column3.first<column3.second&&i+column3.first<total){cout<<" ";cout<<setw(5)<<right<<checks[i+column3.first].number_text;cout<<setw(10)<<right<<checks[i+column3.first].money;cout<<' '<<checks[i+column3.first].date;}cout<<'\n';}}return0;}