2020牛客寒假算法基础集训营5

题目链接:https://ac.nowcoder.com/acm/contest/3006#question

每场都非常的稳。。。稳的辣鸡

题目说明:

A.模板                         B.牛牛战队的比赛地      C.C语言IDE      D.牛牛与牛妹的约会

(贪心)                    (三分)                        (大模拟)         (贪心)

E.Enjoy the game       F.碎碎念                        G.街机争霸        H.Hash

(找规律)                 (DP)                          (BFS)           (字符串水题)

I.I题是个签到题          J.牛牛战队的秀场

(水题)                   (思维)

A.模板

题目大意:两个字符串互变,问至少要多少步,变化规则:

  • 将其中任意一个字母替换为另一个
  • 把最后一个字母删除
  • 在尾部添加一个字母

示例

输入

4 3
WXYZ
WXY

输出

1

没什么好说的,先把长度变成一样长,那么就需要$len(a)-len(b)$步,接下来就是将所有不一样字母的个数加起来就好了

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int mac=1e5+10;

char s1[mac],s2[mac];

int main(int argc, char const *argv[])
{
    int n,m;
    scanf ("%d%d",&n,&m);
    scanf ("%s%s",s1,s2);
    int ans=max(n,m)-min(n,m);
    for (int i=0; i<min(n,m); i++){
        if (s1[i]!=s2[i]) ans++;
    }
    printf("%d\n",ans);
    return 0;
}
View Code

B.牛牛战队的比赛地、

题目大意:在x轴上找一点,使得其距离n个点的最大距离最小

示例

输入

3
0 0
2 0
0 2

输出

2

。。。。没注意看题,然后写了个三分套三分,然后发现输出是个$\sqrt{2}$。。。。然后就发现固定在了x轴,那么我们直接三分x轴就好了。不过为了增加精度,我们最后再开方。

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;
 
const int mac=1e5+10;
const int inf=1e9+10;
 
struct node
{
    int x,y;
}pt[mac];
int n;
double sans=inf;
 
double dis(double x)
{
    double ans=0;
    for (int i=1; i<=n; i++){
        double dist=(x-pt[i].x)*(x-pt[i].x)+(pt[i].y)*(pt[i].y);
        ans=max(ans,dist);
    }
    sans=min(sans,ans);
    return ans;
}
 
int main(int argc, char const *argv[])
{
    scanf ("%d",&n);
    int xma=-inf,xmi=inf,yma=-inf,ymi=inf;
    for (int i=1; i<=n; i++){
        int x,y;
        scanf ("%d%d",&x,&y);
        pt[i]=node{x,y};
        xma=max(x,xma);xmi=min(x,xmi);
        yma=max(y,yma);ymi=min(y,ymi);
    }
    double lx=xmi,rx=xma,ly=ymi,ry=yma;
    for (int i=1; i<=50; i++){
        double mid1=(lx+rx)/2;
        double mid2=(mid1+rx)/2;
        ly=ymi,ry=yma;
        if (dis(mid1)<dis(mid2)) rx=mid2;
        else lx=mid1;
    }
    printf("%.5f\n",sqrt(sans));
    return 0;
}
View Code

C.C语言IDE

题目大意:

示例

输入

#include <stdio.h>

int plus(int a, int b)
{
	return a + b;
}
int main()
{
	int a,b;
	scanf("%d%d", &a, &b);
	printf("%d\n", plus(a, b)); 
	return 0;
}

输出

int plus(int,int)
int main()

D.牛牛与牛妹的约会

题目大意:T组数据(5e5)给你$a,b$两点,你要从$a$到$b$,你可以花费1距离/1单位时间,也可以花费1单位时间从$x$位置到$\sqrt[3]{x}$,问你a到b的最少时间。

示例

输入

2
3 -1
1 2

输出

3.442249570
1.000000000

每次走的时候比较直接走和闪现那个更优就行了,如果直接走比闪现更优,说明之后都是直接走更优了,我们break,注意一下pow函数需要对负数特殊处理

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

int main(int argc, char const *argv[])
{
    int t;
    scanf ("%d",&t);
    while (t--){
        int a,b;
        scanf ("%d%d",&a,&b);
        double x=a,y=b,nx;
        double ans=0;
        while(1){
            if (x<0) nx=-pow(-x,1.0/3.0);
            else nx=pow(x,1.0/3.0);
            if (fabs(nx-y)<fabs(x-y)-1) ans+=1,x=nx;//比较两个谁更优
            else {ans+=fabs(x-y); break;}
        }
        printf("%.8f\n",ans);
    }
    return 0;
}
View Code

E.Enjoy the game

题目大意:Bob和Alice博弈,规则如下:

    • 初始一共有n张卡牌
    • 先手第一步最少要拿1张牌,最多要拿n-1张牌。
    • 接下来每一步,双方最少要拿1张牌,最多拿等同于上一步对方拿的牌数的牌。
    • 拿走最后一张牌的人将取得游戏的胜利。

示例

输入

2

输出

Alice

这题,找规律。。。没什么好说的,大胆尝试,交他一发,然后证明了$2^{k}$则Alice获胜,否则就是Bob

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

int main(int argc, char const *argv[])
{
    long long n;
    cin>>n;
    int mark=0;
    while (n>1){
        if (n&1) mark=1;
        n>>=1;
    }
    if (mark) cout<<"Bob"<<endl;
    else cout<<"Alice"<<endl;
    return 0;
}
View Code

F.碎碎念

题目大意:AC一道题会说一句话,RJ一道题会说$x$句话,问,如果他说了$[l,r]$句话,那么他有几种有效提交序列

示例

输入

3
3
3 3
1 4
1 5

输出

2
7
11

一眼DP。。。我们的第$i$句话肯定是由第$i-1$和第$i-x$句或转移过去的那么我们只需要想想怎么转移过去了,我们设$dp[i][0/1]$($dp[i][0]$表示$i-1$句话AC到i),然后$i-x$只能AC状态转移过去即:

$dp[i][0]=dp[i-1][0]+dp[i-1][1]$

$dp[i][1]=dp[i-x][0]$

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const ll mod=1e9+7;
const int mac=1e5+10;

ll dp[mac][5];

int main(int argc, char const *argv[])
{
    int x,q;
    scanf ("%d%d",&x,&q);
    dp[0][0]=1;
    for (int i=1; i<mac; i++){
        if (i<x)
            dp[i][0]=(dp[i-1][0]+dp[i-1][1])%mod;
        else {
            dp[i][0]=(dp[i-1][0]+dp[i-1][1])%mod;
            dp[i][1]=(dp[i-x][0])%mod;
        }
        dp[i][2]=(dp[i][0]+dp[i][1])%mod;
        dp[i][2]=(dp[i][2]+dp[i-1][2])%mod;
    }
    while (q--){
        int l,r;
        scanf ("%d%d",&l,&r);
        ll ans=dp[r][2]-dp[l-1][2];
        ans=(ans+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}
View Code

G.街机争霸

题目大意:

示例

输入

3 3 1 3
&&A
###
&&L
2 1 RIGHT

输出

2

H.Hash

题目大意:给你一个长度为6的字符串和hash值的mod,让你构造一个一样长的字符串,字典序大于原来的,使得其hash值与原来的一样

示例

输入

abcdef 11

输出

abcdeq

。。。实际上就是个26进制的的加法,我们在原来的Hash值上直接加上mod就好了,然后就开始进位就好了

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int LEN = 6;

char s[10];
int mod,p[10];

void solve()
{
    for(int i=0; i<6; i++)
        printf("%c",p[i]+'a');
    printf("\n");
}

int main(int argc, char const *argv[])
{
    while (~scanf ("%s%d",s,&mod)){
        for (int i=0; i<6; i++)
            p[i]=s[i]-'a';
        p[5]+=mod;
        if (p[5]<26) {solve(); continue;}

        p[4]+=p[5]/26;
        p[5]%=26;
        if (p[4]<26) {solve(); continue;}

        p[3]+=p[4]/26;
        p[4]%=26;
        if (p[3]<26) {solve(); continue;}

        p[2]+=p[3]/26;
        p[3]%=26;
        if (p[2]<26) {solve(); continue;}

        p[1]+=p[2]/26;
        p[2]%=26;
        if (p[1]<26) {solve(); continue;}

        p[0]+=p[1]/26;
        p[1]%=26;
        if (p[0]<26) {solve(); continue;}

        printf("-1\n");
    }
    return 0;
}
View Code

I.I题是个签到题

题目大意:给你n,m(题目数量,总人数)和n道题的过题人数,然后让你判断I题是否是签到题(有80%的人过了或者过题人数前3名的)

示例

输入

9 100
100 100 100 100 100 100 100 100 100

输出

Yes

这题确实是个签到题。。。不过需要注意的是人数会有小数点所以要特判一下。。。我就是这里被卡了10来min。。。。

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;
 
int a[20];
 
bool cmp(int x,int y)
{
    return x>y;
}
 
int main(int argc, char const *argv[])
{
    int n,m;
    scanf ("%d%d",&n,&m);
    int nb=m*0.8;
    if (4*m%5) nb++;//!注意
    int mark=0,val;
    for (int i=1; i<=n; i++){
        int x;
        scanf ("%d",&x);
        a[i]=x;
        if (i==9) val=x;
        if (i==9 && x>=nb) mark=1;
    }
    sort(a+1,a+1+n,cmp);
    if (mark) printf("Yes\n");
    else {
        if (val>=a[3]) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
View Code

J.牛牛战队的秀场

题目大意:给你正n边形和其外接圆的半径,问你从第i个顶点到第j个顶点的最短路径是多少(编号是从1开始顺时针编号)

示例

输入

4 1
1 2

输出

1.414214

题目理解错了,我以为只能顺时针走。。。。然后卡了好久。。。我们先算出这个正n边形的边长,这个很好算:

 

 n边形可以分解成n个一模一样的等腰三角形,一个等腰三角形又可以拆成2个一模一样的直角三角形,那么角1的度数就很好算了:$\angle 1=\frac{360}{2n}=\frac{\pi }{n}$

那么根据三角函数,$x$也就出来了:$x=2rsin\angle 1$

最后我们取顺时针到j点和逆时针到j点的最小值

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;
  
const double pi=acos(-1);
  
int main(int argc, char const *argv[])
{
    int n,r;
    scanf ("%d%d",&n,&r);
    int i,j;
    scanf ("%d%d",&i,&j);
    double a=pi/n;
    double len=2.0*r*sin(a);
    double ans1,ans2;
     
    ans1=len*n;
    ans1-=1.0*abs(i-j)*len;
 
    ans2=1.0*abs(i-j)*len;
 
    printf("%.7f\n",min(ans1,ans2));
    return 0;
}
View Code
posted @ 2020-02-22 18:39  lonely_wind  阅读(288)  评论(0编辑  收藏  举报