2020牛客暑期多校训练营(第二,三场)补题

第二场

C题目

在这里插入图片描述

题意: 无根树,找出没有两端均与其他数字相连的数字并以最少的线段与其他数字相连,输出要连线的线段数和连线的情况。

#include<bits/stdc++.h>
using namespace std;
int a[201010],n,u,v,tmp,tree[201010];
int main()
{
    
    
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1; i<n; i++)
    {
    
    
        cin>>u>>v;
        a[u]++;
        a[v]++;
    }
    for(int i=1; i<=n; i++)
    {
    
    
        if(a[i]==1)
        {
    
    
            tmp++;
            tree[tmp]=i;
        }
    }
    cout<<((tmp+1)>>1)<<endl;//tmpd的一半
    for(int i=1; i<=((tmp+1)>>1); i++)
        cout<<tree[i]<<" "<<tree[i+(tmp>>1)]<<endl;
}

F题目

在这里插入图片描述

题意:以坐标为两数字求其最小公倍数组成二维数组,求边长为K范围内的最大值之和并输出。

#include <iostream>
#include<string.h>
using namespace std;
int m,n,k;

int a[5001][5001];
int lcm(int a,int b)//求a,b的最小公倍数
{
    
    
    int z=a*b;
    int t,p;
    if(a<b)
    {
    
    
        p=a;
        a=b;
        b=p;


    }
    while(b!=0)
    {
    
    
        t=a%b;
        a=b;
        b=t;
    }
    return z/a;
}
int main()
{
    
    

    memset(a,0,sizeof(a));

    for(int i=1; i<=5000; i++)
    {
    
    
        for(int j=1; j<=5000; j++)
        {
    
    
            a[i][j]=lcm(i,j);
        }
    }
    cin>>m>>n>>k;
    long long  int s=0;
    if(k==1)
    {
    
    
        for(int i=k; i<=m; i++)
        {
    
    
            for(int j=k; j<=n; j++)
            {
    
    

                s+=a[i][j];
            }

        }
    }
    else
        for(int i=k; i<=m; i++)
        {
    
    
            for(int j=k; j<=n; j++)
            {
    
    

                a[i][j]=max(max(a[i-1][j],a[i][j-1]),a[i][j]);//最大值均是在右下角
                s+=a[i][j];
            }

        }
    cout << s << endl;
    return 0;
}

B题目

在这里插入图片描述

题意:给你若干个点,找一个过原点的圆使圆上经过的点最多。

公式推导:
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS                     \
    ios::sync_with_stdio(false);\
    cin.tie(0)
pair<int,int> a[2005];

map<pair<double,double>,int> p;///把x,y合并并用map记录

int main()
{
    
    
    IOS;
    int n;
    cin>>n;
    for(int i=0; i<n; i++)
        cin>>a[i].first>>a[i].second;
    int ans=0;
    for(int i=0; i<n; i++)
    {
    
    
        p.clear();
        for(int j=i+1; j<n; j++)
        {
    
    
            double x1=a[i].first,y1=a[i].second,x2=a[j].first,y2=a[j].second;
            if(x1*y2==x2*y1)
                continue;
            double x=(y1*(x2*x2+y2*y2)-y2*(x1*x1+y1*y1))/(y1*x2-y2*x1)/2;///公式求圆心
            double y=(x1*(x2*x2+y2*y2)-x2*(x1*x1+y1*y1))/(y2*x1-y1*x2)/2;
            p[make_pair(x,y)]++;
            ans=max(ans,p[make_pair(x,y)]);///make_pair:无需写出型别, 就可以生成一个pair对象 
        }
    }
    cout<<ans+1<<endl;
    return 0;
}

第三场

A题目

有一个钓鱼游戏如下:

游戏包含 ññ 阶段,从 1个1个 至 ññ。

有四种类型的阶段(从 00 至 33):

类型 00:这个阶段没有鱼,没有蛤。

类型 1个1个:在此阶段没有鱼和一只蛤。

类型 22:这个阶段只有一条鱼,没有蛤。

类型 33:在此阶段有一条鱼和一只蛤c。

在每一个阶段,你可以做准确 以下四种操作之一。

如果舞台上有蛤lam,您可以用这个蛤make制作一包鱼饵。而且,您所拥有的鱼饵包装数将增加一。 在此阶段之后,您可以使用此包鱼饵捕获鱼。

如果舞台上只有一条鱼,则无需任何鱼饵就可以抓到这条鱼。在此阶段之后,您拥有的鱼饵包数不会改变。

如果您有至少一包鱼饵。即使在此阶段没有鱼,也可以始终仅使用一包鱼饵捕获一条鱼。在此阶段之后,您拥有的鱼饵包数将减少一。

你什么也做不了。

现在,给你 ññ以及每个阶段的类型 请计算您可以在钓鱼游戏中获得的最大鱼类数量。
在这里插入图片描述

题意:在不同的阶段内求出最多种类的鱼

#include <bits/stdc++.h>

using namespace std;

int main()
{
    
    
    int n;
    cin >> n;
    while(n--)
    {
    
    
        int t,f = 0,b=0;
        char a[2000005];
        cin >> t;
        for(int i = 0; i < t; i++)
        {
    
    
            cin >> a[i];
            if(b>0&&a[i] == '0')
            {
    
    
                f++;
                b--;
            }
            if(a[i] == '2'||a[i] == '3')///当有鱼时一定要选鱼
                f++;
            if(a[i] == '1')
                b++;
        }
        f+=b/2;///当有2个一时,可以选择阶段一:变鱼饵,阶段二:用鱼饵钓鱼
        cout << f<<endl;
    }
    return 0;
}

B题目

链接:https://ac.nowcoder.com/acm/contest/5668/B
来源:牛客网

Given a string S consists of lower case letters. You’re going to perform Q operations one by one. Each operation can be one of the following two types:

Modify: Given an integer x. You need to modify S according to the value of x. If x is positive, move the leftmost x letters in S to the right side of S; otherwise, move the rightmost |x| letters in S to the left side of S.
Answer: Given a positive integer x. Please answer what the x-th letter in the current string S is.
输入描述:
There are Q+2 lines in the input. The first line of the input contains the string S. The second line contains the integer Q. The following Q lines each denotes an operation. You need to follow the order in the input when performing those operations.

Each operation in the input is represented by a character c and an integer x. If c = ‘M’, this operation is a modify operation, that is, to rearrange S according to the value of x; if c = ‘A’, this operation is an answer operation, to answer what the x-th letter in the current string S is.
在这里插入图片描述

题意:给定一个字符串S由小写字母组成。你要一个接一个地执行Q操作。每个操作可以是以下两种类型之一:
Modify:给定一个整数x,需要根据x的值修改S,如果x为正,则将S中最左边的x字母移到S的右侧;否则,将S中最右边的| x |字母移到S的左侧。
答:给定一个正整数x。请回答当前字符串S中的第x个字母是什么。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    
    
    std::ios::sync_with_stdio(false);
    string s,ch;
    cin>>s;
    ll p;
    cin>>p;
    char a;
    ll b,l,w=0;
    l=s.length();
    for(ll i=0; i<p; i++)
    {
    
    
        cin>>a>>b;
        if(a=='A')
            cout<<s[(b-1+w)%l]<<endl;///可以看成循环,不断增减W的值改变初始的那个位置
        else
        {
    
    
            if(b>0)
            {
    
    
                w=w+b;
            }
            else
            {
    
    
                w=(w+l-abs(b)) %l;
            }
        }
    }


    return 0;
}

C题目

在这里插入图片描述
在这里插入图片描述

输入:
2
1.000000 0.000000
10.000000 0.000000
10.000000 8.000000
9.000000 8.000000
9.000000 5.000000
8.000000 5.000000
8.000000 10.000000
7.000000 10.000000
7.000000 5.000000
6.000000 5.000000
6.000000 10.000000
5.000000 10.000000
5.000000 5.000000
4.000000 5.000000
4.000000 10.000000
3.000000 10.000000
3.000000 3.000000
2.000000 3.000000
2.000000 6.000000
1.000000 6.000000
-1.000123 0.000000
-10.000123 0.000000
-10.000123 8.000000
-9.000123 8.000000
-9.000123 5.000000
-8.000123 5.000000
-8.000123 10.000000
-7.000123 10.000000
-7.000123 5.000000
-6.000123 5.000000
-6.000123 10.000000
-5.000123 10.000000
-5.000123 5.000000
-4.000123 5.000000
-4.000123 10.000000
-3.000123 10.000000
-3.000123 3.000000
-2.000123 3.000000
-2.000123 6.000000
-1.000123 6.000000

输出:
right
left

题意:

爱丽丝将给挑战者她手掌的许多手印。挑战者必须正确告诉Alice每个手印是她的左手掌还是右手掌。请注意,爱丽丝手掌的手印由其2D平面坐标按顺时针或逆时针顺序给出。并且形状可以旋转和平移。但是形状不会被放大或缩小。

解题思路:

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1000;
double eps=0.5;
struct node
{
    
    
    double x,y;
} a[N];
int t;
double dist(node a,node b)
{
    
    
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));//边的长度
}
double ji(node a,node b,node c)
{
    
    
    return (a.x-b.x)*(b.y-c.y)-(a.y-b.y)*(b.x-c.x);//两条边的向量积
}
int main()
{
    
    
    scanf("%d",&t);
    while(t--)
    {
    
    
        bool f=0;
        for(int i=0; i<20; i++)
            scanf("%lf %lf",&a[i].x,&a[i].y);
        for(int i=0; i<20; i++)
        {
    
    
            if(fabs(dist(a[i],a[(i+1)%20])-9)<eps)//先找到掌底边
            {
    
    
                if(((ji(a[i],a[(i+1)%20],a[(i+2)%20])<0)&&(fabs(dist(a[(i+1)%20],a[(i+2)%20])-8)<eps))||(fabs(dist(a[(i+1)%20],a[(i+2)%20])-6)<eps&&ji(a[i],a[(i+1)%20],a[(i+2)%20])>0))//如果满足左手掌的叉乘积,即为左手
                    f=1;
            }
        }
        if(f==1)
            puts("left");
        else
            puts("right");
    }
}

F题目

在这里插入图片描述

输入:
3
4 1
1 6
37 111
输出:
-1 -1 -1 -1
1 2 1 3
145 87 104 78

题解:
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int p=1;
int gcd(int a,int b)
{
    
    
    return b?gcd(b,a%b):a;///求a,b的最大公约数
}
int exgcd(int a,int b,ll &x,ll &y)
{
    
    
    if(b==0)
    {
    
    
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,x,y);
    ll z=x;
    x=y;
    y=z-y*1ll*(a/b);
    return d;
}
int main()
{
    
    
    int T;
    scanf("%d",&T);
    while(T--)
    {
    
    
        int a,b;
        scanf("%d %d",&a,&b);
        int gc=gcd(a,b);
        if(gc!=1)
        {
    
    
            printf("%d %d %d %d\n",a/gc+1,b/gc,p,b/gc);//若不为互质则按公式接出
        }
        else
        {
    
    
            int d=0,f=0;
            for(int i=2; i*i<=b; ++i)
            {
    
    
                if(b%i==0&&gcd(i,b/i)==1)
                {
    
    
                    d=i;
                    f=b/i;
                    break;
                }
            }
            if(d==0&&f==0)
            {
    
    
                printf("-1 -1 -1 -1\n");
            }
            else///若找到两数互质且相乘为b
            {
    
    
                ll c,e;
                int x=exgcd(f,d,c,e);
                c*=1ll*a,e*=1ll*a;
                if(c>0&&e<0)
                {
    
    
                    printf("%lld %d %lld %d\n",c,d,-e,f);
                }
                else
                {
    
    
                    printf("%lld %d %lld %d\n",e,f,-c,d);
                }
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cuijunrongaa/article/details/107424647