灵动ICPC冬令营基础-2
A - Maya Calendar
上周末,M. A. Ya教授对古老的玛雅有了一个重大发现。从一个古 老的节绳(玛雅人用于记事的工具)中,教授发现玛雅人使用 Haab历法,一年有365天。Haab历法每年有19个月,在前18个月, 每月有20天,月份的名字分别是pop, no, zip, zotz, tzec, xul, yoxkin, mol, chen, yax, zac, ceh, mac, kankin, muan, pax, koyab, cumhu。这 些月份中的日期用0到19表示;Haab历的最后一个月叫做uayet, 它只有5天,用0到4表示。玛雅人认为这个日期最少的月份是不 吉利的:在这个月,法庭不开庭,人们不从事交易,甚至不打扫 房屋。
• 因为宗教的原因,玛雅人还使用了另一个历法,这个历法中年被 称为Tzolkin历法(holly年),一年被分成13个不同的时期,每个 时期有20天,每一天用一个数字和一个单词相组合的形式来表示。 使用的数字是1~13,使用的单词共有20个,它们分别是:imix, ik, akbal, kan, chicchan, cimi, manik, lamat, muluk, ok, chuen, eb, ben, ix, mem, cib, caban, eznab, canac, ahau。注意:年中的每一天都有着 明确唯一的描述,比如,在一年的开始,日期如下描述: 1 imix, 2 ik, 3 akbal, 4 kan, 5 chicchan, 6 cimi, 7 manik, 8 lamat, 9 muluk, 10 ok, 11 chuen, 12 eb, 13 ben, 1 ix, 2 mem, 3 cib, 4 caban, 5 eznab, 6 canac, 7 ahau, 8 imix, 9 ik, 10 akbal ……也就是说数字和单词各自独 立循环使用。
• Haab历和Tzolkin历中的年都用数字0,1,……表示,数字0表示世 界的开始。所以第一天被表示成:
• Haab: 0. pop 0
• Tzolkin: 1 imix 0
• 请您帮助M. A. Ya教授,编写一个程序,把Haab历转化成Tzolkin历。
• 输入
• Haab历中的数据由如下的方式表示:
• NumberOfTheDay. Month Year(日期. 月份 年数)
• 输入中的第一行表示要转化的Haab历日期的数据量。接下来的每一行 表示一个日期,年数小于5000。
• 输出
• Tzolkin历中的数据由如下的方式表示:
• Number NameOfTheDay Year(天数字 天名称 年数)
• 第一行表示输出的日期数量。下面的每一行表示一个输入数据中对应 的Tzolkin历中的日期。
#include<stdio.h>
#include<string.h>
char h[25][10]={"pop","no", "zip", "zotz","tzec" ,"xul","yoxkin","mol", "chen","yax", "zac","ceh","mac","kankin","muan","pax","koyab","cumhu","uayet "};
char num[30][10]={" ","imix","ik","akbal", "kan","chicchan","cimi","manik","lamat","muluk","ok","chuen","eb","ben","ix","mem","cib","caban","eznab","canac","ahau"};
int main(){
int i,k,j,day,years,current=0,years1[4],num1[4],word1[4],t;
char mouse[10];
int n;
scanf("%d",&n);
while(n--){
scanf("%d.%s%d",&day,mouse,&years);
for(i=0;i<19;i++){
if((strcmp(h[i],mouse))==0) {
k=i;
}
}
current=day+1+20*k+365*years;
if(current%260==0){
years1[j]=current/260-1;
num1[j]=13;
word1[j]=20;
}
else{
years1[j]=current/260;
num1[j]=(current%13==0?13:current%13);
word1[j]=(current-1)%20+1;
}
j++;
}
printf("%d\n",j);
for(i=0;i<j;i++){
printf("%d %s %d\n",num1[i],num[word1[i]],years1[i]);
}
return 0;
}
B - Diplomatic License
• 为了尽量减少外交开支,世界各国讨论如下。每一个国家最多只与一个国家 保持外交关系是不够的,因为世界上有两个以上的国家,有些国家不能通过 (一连串的)外交官进行相互交流。
• 本题设定每个国家最多与另外两个国家保持外交关系。平等对待每个国家是 一条不成文的外交惯例。因此,每个国家都与另外两个国家保持外交关系。
• 国际地形学家提出一种适合这一需求的结构。他们将安排国家组成一个圈, 使得每个国家都与其左右两个邻国建立外交关系。在现实世界中,一个国家 的外交部是设在这个国家的首都。为了简单起见,本题设定,首都的位置是 二维平面上的一个点。如果您用直线把保持外交关系的相关国家的外交部联 起来,结果就是一个多边形。
• 现在,要为两个国家之间的双边外交会议设定地点。同样,出于外交原因, 两国的外交官前往该地点的距离必须相等。为了提高效率,应尽量缩短行驶 距离,请您为双边外交会议做好准备。
• 输入
• 输入给出若干测试用例。每个测试用例首先给出数字n,表示涉及n个 国家。本题设定n3是一个奇数。然后,给出n对x和y坐标,表示外交 部的位置。外交部的坐标是绝对值小于1012的整数。国家的排列顺序 与它们在输入中出现的顺序相同。此外,在列表中,第一个国家是最 后一个国家的邻国。
• 输出
• 对于每个测试用例,首先输出测试用例中国家的数量(=n),然后给 出国家之间的双边外交会议地点位置的x和y坐标。输出的会议地点的 顺序应与输入给出的顺序相同。从排在最前的两个国家的会议地点开 始,一直到排在最后面的两个国家的会议地点,最后输出第n个国家和 第一个国家的会议地点。
#include<cstdio>
#include<algorithm>
#define cord std::pair<double ,double >
#define x first
#define y second
const int N =1001;
cord loc[N];
typedef struct{
double x1;
double y1;
}wol;
wol w[N];
int main(){
int n,i;
while(~scanf("%d",&n)){
for(i=1;i<=n;i++) scanf("%lf%lf",&loc[i].x,&loc[i].y);
for(i=1;i<n;i++){
w[i].x1=(loc[i].x+loc[i+1].x)/2;
w[i].y1=(loc[i].y+loc[i+1].y)/2;
}
w[n].x1=(loc[1].x+loc[n].x)/2;
w[n].y1=(loc[1].y+loc[n].y)/2;
printf("%d ",n);
for(i=1;i<=n;i++){
printf("%lf %lf ",w[i].x1,w[i].y1);
}
printf("\n");
}
return 0;
}
C - “Accordian” Patience
• 请您模拟"Accordian" Patience游戏,规则如下:
• 玩家将一副扑克牌一张一张地发牌,从左到右排成一排,不能重叠。 只要一张扑克牌和左边的第一张牌或左边的第三张牌相匹配,就将这 张扑克牌移被匹配的牌的上面。所谓两张牌匹配是这两张牌的数值 (数字或字母)相同或花色相同。每当移了一张牌之后,就再检查看 这张牌能否继续往左移,每次只能移在牌堆顶部的牌。本游戏可以将 两个牌堆变成一个牌堆,如果根据规则,可以将右侧牌堆的牌一张一 张地移到左侧牌堆,就可以变成一个牌堆。本游戏尽可能地把牌往左 边移动。如果最后只有一个牌堆,玩家就赢了。
• 在游戏过程中,玩家可能会遇上一次可以有多种选择的情况。当两张 牌都可以被移动时,就移动最左边的牌。如果一张牌可以向左移动一 个位置或向左移动三个位置,则将其移动三个位置。
• 输入
• 输入给出发牌的顺序。每个测试用例由一对行组成,每行给出26 张牌,由单个空格字符分隔。输入文件的最后一行给出一个#作 为其第一个字符。每张扑克牌用两个字符表示。第一个字符是面 值(A=Ace,2-9,T=10,J=Jack,Q=Queen,K=King),第二个字 符是花色(C= Clubs(梅花),D=Diamonds(方块),H=Hearts (红心),S=Spades(黑桃))。
• 输出
• 对于输入中的每一对行(一副扑克牌的52张牌),输出一行,给 出在对应的输入行进行游戏后,每一堆扑克牌中剩余的扑克牌的 数量。
#include<cstdio>
using namespace std;
const int N = 55;
char s[N][N][N];
int pre[N], last[N], mp[N], sum[N], ans[N];
int getp3(int x) {
int p1 = pre[x], p2 = pre[p1], p3 = pre[p2];
return p3;
}
int getp1(int x) {
int p1 = pre[x];
return p1;
}
int main() {
while(1) {
scanf("%s", s[1][1]);
if(s[1][1][0] == '#') break;
last[1] = 2; sum[1] = 1; last[0] = 1;
for(int i = 2; i <= 52; i++) {
scanf("%s", s[i][1]);
pre[i] = i - 1;
last[i] = i + 1;
sum[i] = 1;
}
for(int i = 2; i <= 52; i = last[i]) {
int p = getp3(i);
if(p > 0 && (s[p][sum[p]][0] == s[i][sum[i]][0] || s[p][sum[p]][1]
== s[i][sum[i]][1])) {
sum[p]++;
s[p][sum[p]][0] = s[i][sum[i]][0];
s[p][sum[p]][1] = s[i][sum[i]][1];
sum[i]--;
if(sum[i] == 0) {
last[pre[i]] = last[i];
pre[last[i]] = pre[i];
}
i = p - 1;
continue;
}
p = getp1(i);
if(p > 0 && (s[p][sum[p]][0] == s[i][sum[i]][0] || s[p][sum[p]][1]
== s[i][sum[i]][1])) {
sum[p]++;
s[p][sum[p]][0] = s[i][sum[i]][0];
s[p][sum[p]][1] = s[i][sum[i]][1];
sum[i]--;
if(sum[i] == 0) {
last[pre[i]] = last[i];
pre[last[i]] = pre[i];
}
i = p - 1;
continue;
}
}
int cnt = 0;
for(int i = 1; i <= 52; i++) {
if(sum[i]) ans[cnt++] = sum[i];
}
printf("%d piles remaining: %d", cnt, ans[0]);
for(int i = 1; i < cnt; i++) {
printf(" %d", ans[i]);
}
printf("\n");
}
return 0;
}
D - Broken Keyboard (a.k.a. Beiju Text)
•您正在用一个坏键盘键入一个长文本。这个键盘的 问题是时不时“Home”键或“End”键会在您输入 文本时自动按下。您并没有意识到这个问题,因为 你只关注文本,甚至没有打开显示器。完成键入后, 您打开显示器,在屏幕上看到文本。在中文里,我 们称之为悲剧。请您是找到悲剧的文本。
• 输入
• 输入给出若干测试用例。每个测试用例都是一行,包含至少一个, 最多100,000个字母、下划线和两个特殊字符‘[’和‘]’;其中‘[’表示 “Home”键,而‘]’表示“End”键。输入以EOF结束。 • 输出
• 对于每个测试用例,输出在屏幕上的悲剧的文本。
#include<cstdio>
using namespace std;
string str,ans;
const int N = 1e5+10;
int Nex[N];
void solve(){
int pos = 0,ls = 0;
Nex[0] = 0; str = "#" + str;
for(int i = 1; str[i]; i++){
if(str[i] == '[') pos = 0;
else if(str[i] == ']') pos = ls;
else{
Nex[i] = Nex[pos];
Nex[pos] = i;
if(pos == ls) ls = i;
pos = i;
}
}
for(int i = Nex[0]; i;i = Nex[i])
cout << str[i];
cout << endl;
}
int main(){
while(getline(cin,str)){
for(int i = 1;i <= 10;i++);
solve();
}
return 0;
}
E - Satellites
• 输入
• 输入包含一个或多个测试用例。
• 每个测试用例一行,给出两个整数s和a,以及一个字符串”min” 或”deg”;其中s是人造卫星与地球表面的距离,a是这两颗人造卫 星对地球中心的夹角。以分(′),或者以度(◦),为单位。输入不会 既给出分,又给出度。
• 输出
• 对于每个测试用例,输出一行,给出两个卫星之间的圆弧距离和 直线弦距离,以公里为单位。距离是一个浮点数,保存小数点后 的六位数字。
#include<cstdio>
#include<cmath>
#include<iostream>
#define pi atan(1.0)*4
int main(){
double s,a,arc,dist;
char c[4];
while(~scanf("%lf%lf%s",&s,&a,c)){
if(c[0]=='m') a/=60;
if(a>180) a=360-a;
arc=2*pi*(s+6440.0)*a/360;
dist=(s+6440.0)*sin(a*pi/360)*2;
printf("%.6lf %.6lf\n",arc,dist);
}
return 0;
}
F - Fourth Point !!
•给出平行四边形中两条相邻边的端点 的(x, y)坐标,请找到第四个点的(x, y) 坐标。
• 输入
• 输入的每行给出8个浮点数:首先,给出第一条边的一个端点和 另一个端点的(x, y)坐标;然后,给出第二条边的一个端点和另一 个端点的(x, y)坐标;所有的坐标均以米为单位,精确到毫米。所 有的坐标的值在-10000和+10000之间。输入以EOF终止。
• 输出
• 对于每行输入,输出平行四边形的第四个点的(x, y)坐标,以米为 单位,精确到毫米,用一个空格隔开x和y。
#include<cstdio>
#include<algorithm>
#define cord std::pair<double ,double >
#define x first
#define y second
const int N =1001;
cord loc[N];
typedef struct{
double x1;
double y1;
}wol;
wol w[N];
int main(){
int i,k=1;
while(1){
for(i=1;i<=4;i++) scanf("%lf%lf",&loc[i].x,&loc[i].y);
for(i=1;i<=4;i++){
if(loc[i].x ==loc[i+1].x){
w[k].x1=loc[i].x;
w[k].y1=loc[i].y;
i++;
}
else{
w[k].x1=loc[i].x;
w[k].y1=loc[i].y;
}
k++;
}
w[4].x1=w[3].x1+w[1].x1-w[2].x1;
w[4].y1=w[3].y1+w[1].y1-w[2].y1;
printf("%.3lf %.3lf\n",w[4].x1,w[4].y1);
k=1;
}
return 0;
}
G - The Circumference of the Circle
•要计算圆的周长似乎是一件容易的事,只 要您知道圆的直径。但是,如果您不知道 呢?给出平面上的3个非共线点的笛卡尔 坐标。你的工作是计算与这3个点相交的 唯一的圆的周长。
• 输入
• 输入包含一个或多个测试用例,每个测试用例一行,包含6个实 数x1 , y1 , x2 , y2 , x3 , y3 ,表示3个点的坐标。由这3个点确定的直径不 超过1百万。输入以文件结束终止。
• 输出
• 对每个测试用例,输出一行,给出一个实数,表示3个点所确定 圆的周长。输出的周长精确到小数两位。Pi的值为 3.141592653589793。
#include<cstdio>
#include<iostream>
#include<cmath>
double dis(double x1,double y1,double x2,double y2){
return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
}
int main(){
double x1,x2,x3,y1,y2,y3;
while(~scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3)){
double c1,c2,c3,x,s,d,l;
c1=dis(x1,y1,x2,y2);
c2=dis(x2,y2,x3,y3);
c3=dis(x3,y3,x1,y1);
x=(c1+c2+c3)/2.0;
s=sqrt(x*(x-c1)*(x-c2)*(x-c3));
d=(c1*c2*c3)/(2.0*s);
l=d*acos(-1.0);
printf("%.2lf\n",l);
}
return 0;
}
H - Titanic
• 这是一个历史事件,在“泰坦尼克号”的传奇航程中,无线电已经 接到了6封电报警告,报告了冰山的危险。每封电报都描述了冰 山所在的位置。第5封警告电报被转给了船长。但那天晚上,第6 封电报被延误,因为电报员没有注意到冰山的坐标已经非常接近 当前船的位置了。
• 请您编写一个程序,警告电报员冰山的危险!
• 输入
• 输入电报信息的格式如下:
• Message #.
• Received at ::.
• Current ship’s coordinates are
• x1^y1’z1" <nl/sl>
• and x2^y2’z2"<el/wl> .
• An iceberg was noticed at
•a1 ^b1’c1"<nl\sl>
• and a2^b2’c2"<el/wl> .
• ===
• 这里的是一个正整数,<>:<>:<>是接收到电报的时间; x1^y1’z1" 和a1^b1’c1" 表示"北(南)纬 x1度x2分x3秒 和东(西)经Y1度Y2分Y3秒。"
#include<cstdio>
#include<iostream>
#include<cmath>
double dis(double x1,double y1,double x2,double y2){
return sqrt(pow(x1-x2,2)+pow(y1-y2,2));
}
int main(){
double x1,x2,x3,y1,y2,y3;
while(~scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3)){
double c1,c2,c3,x,s,d,l;
c1=dis(x1,y1,x2,y2);
c2=dis(x2,y2,x3,y3);
c3=dis(x3,y3,x1,y1);
x=(c1+c2+c3)/2.0;
s=sqrt(x*(x-c1)*(x-c2)*(x-c3));
d=(c1*c2*c3)/(2.0*s);
l=d*acos(-1.0);
printf("%.2lf\n",l);
}
return 0;
}