ICPC训练联盟2021寒假冬令营(2)(部分题解)

ICPC训练联盟2021寒假冬令营(2)(部分题解)


B - Diplomatic License
In an effort to minimize the expenses for foreign affairs the countries of the world have argued as follows. It is not enough that each country maintains diplomatic relations with at most one other country, for then, since there are more than two countries in the world, some countries cannot communicate with each other through (a chain of) diplomats.

Now, let us assume that each country maintains diplomatic relations with at most two other countries. It is an unwritten diplomatic “must be” issue that every country is treated in an equal fashion. It follows that each country maintains diplomatic relations with exactly two other countries.

International topologists have proposed a structure that fits these needs. They will arrange the countries to form a circle and let each country have diplomatic relations with its left and right neighbours. In the real world, the Foreign Office is located in every country’s capital. For simplicity, let us assume that its location is given as a point in a two-dimensional plane. If you connect the Foreign Offices of the diplomatically related countries by a straight line, the result is a polygon.

It is now necessary to establish locations for bilateral diplomatic meetings. Again, for diplomatic reasons, it is necessary that both diplomats will have to travel equal distances to the location. For efficiency reasons, the travel distance should be minimized. Get ready for your task!
Input
The input contains several testcases. Each starts with the number n of countries involved. You may assume that n>=3 is an odd number. Then follow n pairs of x- and y-coordinates denoting the locations of the Foreign Offices. The coordinates of the Foreign Offices are integer numbers whose absolute value is less than 1012. The countries are arranged in the same order as they appear in the input. Additionally, the first country is a neighbour of the last country in the list.
Output
For each test case output the number of meeting locations (=n) followed by the x- and y-coordinates of the locations. The order of the meeting locations should be the same as specified by the input order. Start with the meeting locations for the first two countries up to the last two countries. Finally output the meeting location for the n-th and the first country.
Sample Input
5 10 2 18 2 22 6 14 18 10 18
3 -4 6 -2 4 -2 6
3 -8 12 4 8 6 12
Sample Output
5 14.000000 2.000000 20.000000 4.000000 18.000000 12.000000 12.000000 18.000000 10.000000 10.000000
3 -3.000000 5.000000 -2.000000 5.000000 -3.000000 6.000000
3 -2.000000 10.000000 5.000000 10.000000 -1.000000 12.000000
Hint
Note that the output can be interpreted as a polygon as well. The relationship between the sample input and output polygons is illustrated in the figure on the page of Problem 1940. To generate further sample input you may use your solution to that problem.

题意:输出两国之间中点坐标,最后一个国家输出与第一个国家的中点:
代码:

#include<iostream>
#include<stdio.h>   //选择g++编译scanf/printf需要包含
#include<cmath>
#include<string.h>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
#define N 10005
typedef long long int ll;
struct ob{
    ll x;
    ll y;
}hb[N];
int main(){
    int n;
    while(cin>>n){
        cout<<n<<' ';
        for(int i=0;i<n;i++)
        cin>>hb[i].x>>hb[i].y;
        
        for(int i=0;i<n;i++)
        {
            double xi,yi;
            xi=(hb[i].x+hb[(i+1)%n].x)/2.0;
            yi=(hb[i].y+hb[(i+1)%n].y)/2.0;
            printf("%.6llf %.6llf ",xi,yi);
        }
        cout<<endl;
    }
    return 0;
}

C - “Accordian” Patience
You are to simulate the playing of games of ``Accordian’’ patience, the rules for which are as follows:

Deal cards one by one in a row from left to right, not overlapping. Whenever the card matches its immediate neighbour on the left, or matches the third card to the left, it may be moved onto that card. Cards match if they are of the same suit or same rank. After making a move, look to see if it has made additional moves possible. Only the top card of each pile may be moved at any given time. Gaps between piles should be closed up as soon as they appear by moving all piles on the right of the gap one position to the left. Deal out the whole pack, combining cards towards the left whenever possible. The game is won if the pack is reduced to a single pile.
Situations can arise where more than one play is possible. Where two cards may be moved, you should adopt the strategy of always moving the leftmost card possible. Where a card may be moved either one position to the left or three positions to the left, move it three positions.
Input
Input data to the program specifies the order in which cards are dealt from the pack. The input contains pairs of lines, each line containing 26 cards separated by single space characters. The final line of the input file contains a # as its first character. Cards are represented as a two character code. The first character is the face-value (A=Ace, 2-9, T=10, J=Jack, Q=Queen, K=King) and the second character is the suit (C=Clubs, D=Diamonds, H=Hearts, S=Spades).
Output
One line of output must be produced for each pair of lines (that between them describe a pack of 52 cards) in the input. Each line of output shows the number of cards in each of the piles remaining after playing ``Accordian patience’’ with the pack of cards as described by the corresponding pairs of input lines.
Sample Input
QD AD 8H 5S 3H 5H TC 4D JH KS 6H 8S JS AC AS 8D 2H QS TS 3S AH 4H TH TD 3C 6S
8C 7D 4C 4S 7S 9H 7C 5D 2S KD 2D QH JD 6D 9D JC 2C KH 3D QC 6C 9S KC 7H 9C 5C
AC 2C 3C 4C 5C 6C 7C 8C 9C TC JC QC KC AD 2D 3D 4D 5D 6D 7D 8D TD 9D JD QD KD
AH 2H 3H 4H 5H 6H 7H 8H 9H KH 6S QH TH AS 2S 3S 4S 5S JH 7S 8S 9S TS JS QS KS

Sample Output
6 piles remaining: 40 8 1 1 1 1
1 piles remaining: 52
题意:发52张牌,从第二张开始往前匹配,如果某堆牌左边第一堆或者第三堆的牌和其匹配上(同时匹配上优先处理第三堆,并且匹配上指的是花色或者点数匹配上)
就将次堆顶的牌移往第一or第三堆,每次都只能操作堆顶,直到这堆牌全移出去为止。
因此我们可以用五十二个栈来模拟这个过程,我们可以把五十二张牌依次放入栈中,处理的顺序按照放的顺序即可
代码:

#include<iostream>
#include<stdio.h>   //选择g++编译scanf/printf需要包含
#include<cmath>
#include<string.h>
#include<set>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
#define N 10005
typedef long long int ll;
stack<string>s[55];
bool match_card(int a, int b)
{
    if (s[a].top()[0]==s[b].top()[0] || s[a].top()[1]==s[b].top()[1]) return true;
    return false;
}
int main(){
    string str;
    while(cin>>str&&str!="#"){
        int k=0;
        s[k++].push(str);   //第一张牌入栈
        while(k<52){
            cin>>str;
            s[k++].push(str);
        }
        int i=1;    //从第二堆开始找
        int n=k;
        while(i<n){
            int f=0;
            if(i>=1&&match_card(i,i-1)) f=1;
            if(i>=3&&match_card(i,i-3)) f=3;
            if(f){
                string tm=s[i].top();
                s[i].pop();
                s[i-f].push(tm);
                if(s[i].empty())    //牌堆空了将后面的牌往前移,若是最后一堆(i=n-1)就不移动
                {
                    for(int j=i;j<n-1;j++)
                        s[j]=s[j+1];
                    n--;            //牌堆数少一
                }
                i-=(f+1);               //每次移动过后再往前退一步,重新遍历牌堆
            }
            i++;
        }
        cout<<n<<" piles remaining: ";
        for(int i=0;i<n;i++)
        cout<<s[i].size()<<" ";
        cout<<endl;
        for(int i=0;i<52;i++)
        while (!s[i].empty())
        {
            s[i].pop();
        }
    }
    return 0;
}

D - Broken Keyboard (a.k.a. Beiju Text)
You’re typing a long text with a broken keyboard. Well it’s not so badly broken. The only problem
with the keyboard is that sometimes the “home” key or the “end” key gets automatically pressed
(internally).
You’re not aware of this issue, since you’re focusing on the text and did not even turn on the
monitor! After you finished typing, you can see a text on the screen (if you turn on the monitor).
In Chinese, we can call it Beiju. Your task is to find the Beiju text.
Input
There are several test cases. Each test case is a single line containing at least one and at most 100,000
letters, underscores and two special characters ‘[’ and ‘]’. ‘[’ means the “Home” key is pressed
internally, and ‘]’ means the “End” key is pressed internally. The input is terminated by end-of-file
(EOF).
Output
For each case, print the Beiju text on the screen.
Sample Input
This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University
Sample Output
BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University
题意:[是光标回到字符串开始位置,]是光标来到字符串结束的位置,最后根据输入以及光标变换情况输出结果

错误代码(时间超限):

//想着用string插入删除很方便,应该不会超时,结果还是超时了(不知道是不是某个样例死循环或者其他什么情况)
#include<iostream>
#include<stdio.h>   //选择g++编译scanf/printf需要包含
#include<cmath>
#include<string.h>
#include<set>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
#define N 100005
typedef long long int ll;
int main(){
    char str[N];
    while (cin>>str)
    {
        int l=strlen(str);
        int i=0;
        string s;
        int t=0;
        while(i<l){
            if(str[i]=='['){
                t=0;
                i++;
                continue;
            }
            if(str[i]==']'){
                t=s.end()-s.begin();
                i++;
                continue;
            }
            string tm;
            tm+=str[i];
            s.insert(t,tm);
            t++;
            i++;
        }
        cout<<s<<endl;
    }
    return 0;
}

1.AC(代码,正宗链表实现,vj测试数据耗时170ms)

#include<iostream>
#include<stdio.h>   //选择g++编译scanf/printf需要包含
#include<cmath>
#include<string.h>
#include<set>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
#define N 100005
typedef long long int ll;
struct nd
{
    char c;         //节点信息
    nd* next;
};
int main()
{
    string str;
    while(cin>>str)
    {
        nd *head;
        nd *p,*cur,*tm;
        head=new nd;
        head->c='!';
        head->next=nullptr;
        p=cur=head;
        for(int i=0;i<str.size();i++)
        {
            if(str[i]=='[') cur=head;
            else if(str[i]==']') cur=p;
            else
            {
                tm=new nd;
                tm->c=str[i];
                tm->next=nullptr;

                tm->next=cur->next;
                cur->next=tm;
                if(cur==p){
                    p=p->next;
                }
                cur=cur->next;      //光标后移
            }
            
        }
        for(nd* t=head->next;t!=NULL;t=t->next)     //第一个空节点不输出
        cout<<t->c;
        cout<<endl;
    }
    return 0;
}

2.AC代码(用list,时间在200ms附近)

#include<iostream>
#include<stdio.h>   //选择g++编译scanf/printf需要包含
#include<cmath>
#include<string.h>
#include<set>
#include<list>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
#define N 100005
typedef long long int ll;
int main(){
    string str;
    while (cin>>str)
    {
        list<char>s;
        list<char>::iterator t=s.begin();
        for(int i=0;i<str.size();i++)
        {
            if(str[i]=='[') t=s.begin();
            else if(str[i]==']') t=s.end();
            else s.insert(t,str[i]);
        }
        for(list<char>::iterator i=s.begin();i!=s.end();i++)
        cout<<*i;
        cout<<endl;
    }
    return 0;
}

3.AC代码(网上很多的一种做法,用一维数组+指导向量来模拟链表的插入删除操作)
原文链接:https://blog.csdn.net/qq_41420747/article/details/81811662

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxn 1000
 
int main()
{
    int last,cur,next[maxn];    //last记录末位置,cur指向当前位置,next[]记录输出顺序
    int i;
    char s[maxn];   //输入字符串
    while(scanf("%s",s+1)==1)      //s[0]空出
    {
        last=cur=0;
        next[0]=0;  //next[i]置0,意为不指向任何值
        
        for(i=1;i<=strlen(s+1);i++)
        {
            if(s[i]=='[') cur=0;    //当输入]时,cur光标指向首位置
            else if(s[i]==']')  cur=last;   //当输入]时,cur光标指向末尾
            else    //当读入其他字符时,插值操作
            {
                next[i]=next[cur];
                next[cur]=i;
                if(last==cur)   last=i; //当末尾值和当前光标位置相同时,last和cur一样向i跟进
                cur=i;  //尾光标向后移动 
            }
        }
        //顺次输出 
        for(i=next[0];i!=0;i=next[i])
            printf("%c",s[i]);
        printf("\n");
 
    }
    return 0;
}

AC代码(也是从网上看到的比较巧妙的思路)
原文链接:https://blog.csdn.net/crescent__moon/article/details/8765101

#include<stdio.h>
#include<string.h>
char s[100008],z[100008];
int main()
{
    while(scanf("%s",s)!=EOF)
    {
        int len=strlen(s),i,j;
        for(i=0;i<len;i++)
        {
            if(s[i]=='['||s[i]==']')
            z[i]='\0';
            else z[i]=s[i];
        }
        z[len]='\0';
        for(j=len-1;j>=0;j--)
        {
            if(s[j]=='[')
            printf("%s",z+j+1);
        }
        if(!(s[0]=='['||s[0]==']'))
        printf("%s",z);
        for(j=0;j<len;j++)
        {
            if(s[j]==']')
            printf("%s",z+j+1);
        }
        printf("\n");
    }
    return 0;
}

G - The Circumference of the Circle
To calculate the circumference of a circle seems to be an easy task - provided you know its diameter. But what if you don’t?

You are given the cartesian coordinates of three non-collinear points in the plane.
Your job is to calculate the circumference of the unique circle that intersects all three points.
Input
The input will contain one or more test cases. Each test case consists of one line containing six real numbers x1,y1, x2,y2,x3,y3, representing the coordinates of the three points. The diameter of the circle determined by the three points will never exceed a million. Input is terminated by end of file.
Output
For each test case, print one line containing one real number telling the circumference of the circle determined by the three points. The circumference is to be printed accurately rounded to two decimals. The value of pi is approximately 3.141592653589793.
Sample Input
0.0 -0.5 0.5 0.0 0.0 0.5
0.0 0.0 0.0 1.0 1.0 1.0
5.0 5.0 5.0 7.0 4.0 6.0
0.0 0.0 -1.0 7.0 7.0 7.0
50.0 50.0 50.0 70.0 40.0 60.0
0.0 0.0 10.0 0.0 20.0 1.0
0.0 -500000.0 500000.0 0.0 0.0 500000.0
Sample Output
3.14
4.44
6.28
31.42
62.83
632.24
3141592.65
题意:给三个坐标,能确定一个圆,输出此圆周长(根据海伦公式、面积公式、正、余弦定理可解出外接圆直径)
代码(一行代码警告

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<algorithm>
using namespace std;
#define PI 3.141592653589793
int main()
{
    double x1,y1,x2,y2,x3,y3;
    while(scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3)!=EOF)
    printf("%.2f\n",PI*sqrt(((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1))/(1-((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(x3-x2)*(x3-x2)+(y3-y2)*(y3-y2)-(x3-x1)*(x3-x1)-(y3-y1)*(y3-y1))*((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(x3-x2)*(x3-x2)+(y3-y2)*(y3-y2)-(x3-x1)*(x3-x1)-(y3-y1)*(y3-y1))/(4*((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))*((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2))))));
    return 0;
}

H - Titanic(题面见如下链接)
题面链接:https://vjudge.net/contest/418415#problem/H

题意:根据所给出经纬度算出两点间距离(球体表面两点)
输入太难处理了…已知球体上两点A和B的纬度和经度,分别为(wA,jA)和(wB,jB),计算A和B之间的距离公式:dist(A,B)=R*arccos(cos(wA)*cos(wB)*cos(jA-jB)+sin(wA)*sin(wB));其中R是球体的半径,默认’N’和’E’为正方向,'S’和’W’为负方向。
实在做不动,给个别的大佬做的代码:
原文链接:https://blog.csdn.net/keepkind/article/details/113001058
代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
using namespace std;
double pi=acos(-1.0);		//	acos()函数不接受 int型,否则将编译错误 
double R=3437.5;			//地球半径(英里) 
inline void change(double &x,double &y){
	x=x*pi/180;
	y=y*pi/180;
 }
	//A(wa,jb),B(wx,jy),w 表示维度; j 表示经度。北纬、东经取正 
void distance(double a,double b,double x,double y){
	double d;
	//为计算地球两点的距离公式,请自行推导 
	d=R* acos(cos(a)*cos(x)*cos(b-y)+sin(a)*sin(x));	
	printf("The distance to the iceberg: %.2lf miles.\n",d);
	if(floor(d+0.005)<100)
		cout<<"DANGER!\n";
}
int main(){
	string s;
	double a1,a2,a3,b1,b2,b3,shipw,shipj,icebergw,icebergj;
	char a,b;
	int i;
	for(i=0;i<3;i++)
		getline(cin,s);			
	scanf("%lf^%lf'%lf\" %cL ",&a1,&a2,&a3,&a);	
	scanf("and %lf^%lf'%lf\" %cL.",&b1,&b2,&b3,&b);
			
	shipw=a1+ a2/60+ a3/3600;
	shipj=b1+ b2/60+ b3/3600;
	if(a=='S')	shipw*=-1;
	if(b=='W')	shipj*=-1;
	
	change(shipw,shipj);

	getchar();	//当 getline函数 前使用过 scanf函数 需要getchar()读取未被scanf读到的 \n 
	getline(cin,s);	
	scanf("%lf^%lf'%lf\" %cL ",&a1,&a2,&a3,&a);
	scanf("and %lf^%lf'%lf\" %cL.",&b1,&b2,&b3,&b);
						
	icebergw=a1+ a2/60 +a3/3600;
	icebergj=b1+ b2/60 +b3/3600;
	if(a=='S')	icebergw*=-1;
	if(b=='W')	icebergj*=-1;
	
	change(icebergw,icebergj);
	getchar();
	getline(cin,s);	
	distance(shipw,shipj,icebergw,icebergj);
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值