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

链接:link
来源:牛客网

A 模板

题目描述

用尽可能少的步数将一个字符串转化为另一个字符串,转化规则如下:

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

求最少步数

输入描述

输入数据共33行,第一行包括两个整数 n , m ( 1 ≤ n , m ≤ 1 0 5 ) n,m(1 \leq n,m \leq 10^5) n,m(1n,m105)表示两个字符串的长度
第二行包含一个长度为 n n n的字符串 s 1 s_1 s1,表示第一个字符串。
第三行包含一个长度为 m m m的字符串 s 2 s_2 s2,表示第二个字符串。

思路

做题做多了可能会以为是一个字符串匹配的dp,但一看题目,只能在尾部做添加和删除操作,所以只要前面的修改,不够的添加,就是最少步数了

AC代码

#include
#include
#include
#define maxn 100005
using namespace std;
char word1[maxn],word2[maxn];
int ans;
int main(){
    int n, m;
    scanf("%d%d",&n,&m);
    scanf("%s%s",word1,word2);
    int mn=min(n,m);
    int mx=max(n,m);
    for(int i=0;i<mn;i++){
        if(word1[i]!=word2[i])ans++;
    }
    ans+=mx-mn;
    printf("%d",ans);
}

B 牛牛战队的比赛地

题目描述

由于牛牛战队经常要外出比赛,因此在全国各地建立了很多训练基地,每一个基地都有一个坐标 ( x , y ) (x,y) (x,y)
这周末,牛牛队又要出去比赛了,各个比赛的赛点都在 x x x轴上。牛牛战队为了方便比赛,想找一个到达训练基地最大距离最小的地方作为比赛地。

输入描述

输入数据第一行包含一个整数 N ( 1 ≤ N ≤ 100000 ) N(1 \leq N \leq 100000) N(1N100000),表示牛牛战队训练基地的数量。
接下来 N N N行,每行包括 2 2 2个整数 x , y ( − 10000 ≤ x , y ≤ 10000 ) x,y(-10000 \leq x,y \leq 10000) x,y(10000x,y10000),表示每一个训练基地的坐标。

思路

很容易想到二分答案,答案相当于半径,判断就是对每个点算出在这个半径下能够到达的x轴上的最左点和最右点,所有最右点的最小值大于所有最左点的最大值就表示可以

AC代码

#include
#include
#include
#include
#define maxn 100005
using namespace std;
struct Point{
    double x,y;
}p[maxn];
double l,r;
int n;
int check(double x){
    double resr,resl;
    resr=100000.0,resl=-100000.0;
    for(int i=1;i<=n;i++){
        if(x<fabs(p[i].y))return 0;
        double d=sqrt(x*x-p[i].y*p[i].y);
        resl=max(resl,p[i].x-d);
        resr=min(resr,p[i].x+d);
    }
    if(resr>=resl)return 1;
    return 0;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    r=40000.0;
    l=0.0;
    while(r-l>1e-8){
        double mid=(l+r)/2;
        if(check(mid)==1)r=mid;
        else l=mid;
    }
    printf("%lf",l);
}

C C语言IDE

题目描述

链接:link
来源:牛客网

输入

输入将给出一个在C99标准下可以正常编译运行的C语言代码,同时此份代码具有以下约束:

  • 除引用头文件外,没有其他的编译预处理部分,如:#if,#ifdef,#ifndef,#else,#elif,#endif,#define,#undef,#error,#pragma,_Pragma,#line等。
  • 所有的函数的参数与返回值内不会出现任何形式的数组类型,如:char a[]等,如果有指针,保证指针的一定紧跟在类型名后,如char*,long long*等。保证不会出现函数指针。
  • 由单引号修饰的字符不可能是{,},(,),'或"。
  • 由双引号修饰的字符串内一定不包含{,},(,),‘或",也不包含’/’,’/’,’//'的子串。
  • 不会出现函数内嵌套函数的情况。
  • 不会在/* /内出现/ */的嵌套结构。
  • 不会把一句代码拆成两行写。
  • main函数的返回值一定是int类型。当一个函数没有返回值时,一定有前置void标识。
  • 程序内不会出现const标识符。
    输入数据大小保证小于10KB。

输出

按照以下的格式一行输出一个代码中出现的函数,你可以以任意顺序输出各个函数,每个函数仅可被输出一次。
返回类型名(包括void) 函数名(参数1类型,…,参数n类型)
类型里如有空格,每处最多保留一个空格。

思路

大模拟?

WA代码

不清楚到底有几种变量名。我觉得这题出的让我很难受。没过就不放了

D 牛牛与牛妹的约会

牛牛在辛苦的一天的比赛之后,要去找牛妹玩,其实牛妹那天也在比赛。他为了找到牛妹,要尽快的从自己的比赛地到她的比赛地。还记得吗,比赛地都是只在 x x x轴上,所以两个人的坐标都满足 y = 0 y=0 y=0。牛牛除了可以以
1 1 1单位距离/单位时间的速度移动任意时间以外,还可以花费 1 1 1单位时间进行闪现。每次闪现时,如果当前他的坐标是 x = k x=k x=k。他将闪现到 x = x= x= k 3 \sqrt[3]{k} 3k

思路

开始我以为这题要算出 k − 1 = k 3 k-1=\sqrt[3]{k} k1=3k 的点,也就是 2.32471795 2.32471795 2.32471795左右,然后直接计算出结果。后来发现 k 3 \sqrt[3]{k} 3k 下降的很快。所以直接判断闪现快还是走路快。我在操作的时候,如果 b > a b>a b>a,就让 a , b a,b a,b反向。使得总是 k − 1 k-1 k1 k 3 \sqrt[3]{k} 3k 比较,排除掉 k + 1 k+1 k+1。当然要小心闪现过头往回走的情况。

AC代码

//
//  main.cpp
//  cpp
//
//  Created by ZhuChenyu on 2019/11/08.
//  Copyright © 2019年 ZhuChenyu. All rights reserved.
//
#include
#include
#include
#include
#include
#include
#define MOD 1000000007
#define maxn 1000020
#define INF 2147483647
typedef unsigned float_bits;

using namespace std;

//priority_queue ,greater > que;

int n,T;

int ai,bi;
double a,b;
double ans;

int main()
{
    int i,j,t;
    double k;
    scanf("%d",&T);
    for (t=1;t<=T;t++)
    {
    	scanf("%d%d",&ai,&bi);
    	ans=0;
    	a=ai; b=bi;
    	if (a<b)
    	{
    		a=-a; b=-b;
    	}
    	while (1)
    	{
    		if (a>0) k=pow(a,1.0/3);
    		else k=-pow(-a,1.0/3);
    		if (k<a-1&&k>=b)
    		{
    			a=k;
    			ans=ans+1;
    		}
    		else break;
    	}
    	if (a>0) k=pow(a,1.0/3);
    		else k=-pow(-a,1.0/3);
    	if (fabs(k-b)+1<fabs(a-b))
    		ans=ans+fabs(k-b)+1;
    	else ans=ans+a-b;
    	printf("%.7f\n",ans);
    }

    /*scanf("%d",&n);
    double k;

    for (j=2;j<=2;j++)
    {
    	for (i=1;i<=100000000;i++)
    	{
    		k=(i*1.0)/100000000.0;
    		k=k+j;
    		if (k>0) a=k-1-pow(k,1.0/3);
    		else 
    		{
    			a=k-1+pow(-k,1.0/3);
    		}
    		if (a<(1.0/10000000)&&a>(-1.0/10000000))
    			printf("%.10f : %.10f\n",k,a);
   		}
    }
    //2.32471795
    //2.32471796
    */

 	return 0;
}

E Enjoy the game

题目描述

牛牛战队的三个队员在训练之余会自己口胡了一些题当做平时的益智游戏。有一天牛可乐想出了一个小游戏给另外两名队员玩,游戏规则如下:
初始一共有 n n n张卡牌
先手第一步最少要拿 1 1 1张牌,最多要拿 n − 1 n−1 n1张牌。
接下来每一步,双方最少要拿 1 1 1张牌,最多拿等同于上一步对方拿的牌数的牌。
拿走最后一张牌的人将取得游戏的胜利。
你作为旁观者,看着他们玩的很开心,想参与到这场游戏中来,赌一赌谁会能赢。

输入描述

输入数据包含一个整数 n n n( 2 ≤ n ≤ 1 0 18 2≤n≤10^{18} 2n1018),表示初始卡牌张数。

思路

由于非2的幂的状态一定可以转移成2的幂的状态,且不败。因此谁先到2的幂的状态,谁就输了。

AC代码

#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define lb(x) x&(-x) 
#define maxn 100005
#define mod 998244353 
int main(){    
ll n;    
scanf("%lld",&n);    
if(n&(n-1)) printf("Bob\n");    
else printf("Alice\n");    
return 0;
}

F 碎碎念

题目描述

在ACM比赛里,除了CE以外都是有效的提交。每一个提交都会有其评测的结果,或是AC,或是RJ(Rejected,包含各种不通过的情况)。往往一个人上去提交的时候,总有一个队友会坐在边上等着结果。那个人,往往都是只读题不写题的云选手~
牛牛战队里也有这样的云选手——牛能。当牛能看到有效提交得到了AC以后,都会大呼一声“你好能啊!”,反之,如果得到了RJ的话,就会化身为喷子,说xx句“你能不能行啊!”。大家比赛的都十分紧张,这样的大声呼喊未免会引起旁边队伍的注意。
当然牛牛战队交题的时候也很小心,一旦这一发出现了RJ,下一发有效提交一定能获得AC。
比赛结束了以后,旁边的一支队伍愤怒的跑过来说:你们比赛的时候吵不吵啊,一直在这大吼,吼了这么多句!
激烈的争吵引起了吃瓜群众的注意,吃瓜群众问道:吼了多少句啊,这么讨厌的吗
“啊……我也记不清了,大概是在[L,R]这个区间吧”
作为吃瓜群众的你,想根据这个信息算出,这个队伍有多少种有效提交结果序列的可能呢?

输入描述

输入数据包括单组数据、多组询问。输入第一行包含一个整数 x ( 2 ≤ x ≤ 100   000 ) x(2 \leq x \leq 100\,000) x(2x100000),表示牛能在RJ状态下会说“你能不能行啊!”的句子数量。
第二行包括一个整数 Q ( 1 ≤ Q ≤ 1 0 5 ) Q(1 \leq Q \leq 10^5) Q(1Q105),表示询问数量。
接下来Q行,每行包括两个整数 L , R ( 1 ≤ L ≤ R ≤ 100   000 ) L,R(1 \leq L \leq R \leq 100\,000) L,R(1LR100000),表示每次询问下句子的区间数。
答案对1000000007取模

思路

区间查询可以想到求一个前缀和,关键是每一项怎么求。
每次RJ之后都必定是一次AC,可以理解为,最后一次提交是RJ时,前面一次提交一定不是RJ。
可以想到二维dp, d p [ i ] [ j ] dp[i][j] dp[i][j]表示喊了 i i i声时最后一次提交状态时 j j j时的情况总数,0表示RJ,1表示AC
我们有转移方程
d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] + d p [ i − 1 ] [ 1 ] dp[i][1]=dp[i-1][0]+dp[i-1][1] dp[i][1]=dp[i1][0]+dp[i1][1]
d p [ i ] [ 0 ] = d p [ i − k ] [ 1 ] dp[i][0]=dp[i-k][1] dp[i][0]=dp[ik][1]
然后前缀和就可以啦

AC代码

#include
#include
#define ll long long
#define maxn 100005
#define mod 1000000007
using namespace std;
ll a[maxn][2],sum[maxn];//1最后a了,0最后错了
int k;
int main(){
    scanf("%d",&k);
    a[0][1]=1;
    for(int i=1;i<=100000;i++){
        a[i][1]=a[i-1][0]+a[i-1][1];
        a[i][1]%=mod;
        if(i>=k)a[i][0]=a[i-k][1];
        a[i][0]%=mod;
        //printf("%d %d\n",a[i][0],a[i][1]);
        sum[i]=sum[i-1]+a[i][1]+a[i][0];
        sum[i]%=mod;
    }
    int q,l,r;
    scanf("%d",&q);
    while(q--){
        scanf("%d%d",&l,&r);
        printf("%d\n",(sum[r]-sum[l-1]+mod)%mod);
    }
    return 0;
}

G 街机争霸

题目描述

牛牛战队的队员打完比赛以后又到了日常甩锅的时间。他们心情悲伤,吃完晚饭以后,大家相约到一个街机厅去solo。牛牛和牛能进入了一个迷宫,这个迷宫里除了墙壁的阻拦,还会有僵尸的阻拦。情况十分复杂,牛能为了更快的追逐牛牛,迅速放出了大招,让牛牛原地眩晕,而眩晕的解药,也只有牛能自己拥有。
这一个迷宫可以简化为一个 n n n m m m的矩阵,其中有一些僵尸,这些僵尸会在一个 1 ∗ k 1*k 1k的矩形中来回游走。他不会攻击眩晕状态下的人,只会攻击和他抢地盘的人。这名队员每次移动需要一个单位时间,而且他不能穿墙,不能和僵尸处于同一位置,在追到另一名队员之前也不能停下来。
在这一场追逐战中,要么牛能追逐成功,取得胜利,要么被僵尸击败,牛牛胜利。那谁会是最终的王者呢?

输入描述

输入数据有很多行。第一行输入4个整数 n , m , p , k ( 3 ≤ n , m ≤ 500 , 0 ≤ p ≤ 50 , 2 ≤ k ≤ 10 ) n,m,p,k (3 \leq n,m \leq 500, 0 \leq p \leq 50, 2 \leq k \leq 10) n,m,p,k(3n,m500,0p50,2k10),分别表示迷宫的行、列,僵尸的数量,僵尸来回走动的长度。
第2行到第 n + 1 n+1 n+1行输入一个矩阵,每行输入一个字符串,第 i i i个字符串的第 j j j个字符表示矩阵中第 i i i j j j列的状态,如果字符是#表示是可以走的路,如果是&表示是障碍物,A是被眩晕队员的位置,L是追赶者的位置。
n + 2 n+2 n+2行到第 n + p + 1 n+p+1 n+p+1行每行输入两个整数 x , y x,y x,y和一个字符串,第 i i i行的数据表示第 i i i个僵尸当前时间会从第 x x x y y y列出发,沿着固有的方向前进 k k k个单位时间后折返,再走回它之前的位置,再折返,依照这种方法循环下去。第三个字符串表示僵尸初始行进的方向,UP表示向上走,LEFT表示向左走,DOWN表示向下走,RIGHT表示向右走。数据保证在 k k k个长度内僵尸不会碰到边界或者墙壁。

思路

bfs搜索,注意到每个僵尸都是每 2 ∗ ( k − 1 ) 2*(k-1) 2(k1)个时间一次循环,所以我们会有这么多状态的图,我们只要对vis添加相同的状态就行了,复杂度 O ( n ∗ m ∗ 2 ∗ ( k − 1 ) ) O(n*m*2*(k-1)) O(nm2(k1))

AC代码

#include
#include
#include
using namespace std;
char map[505][505];
int dir[5][5]={{0,1},{0,-1},{1,0},{-1,0}};
int n,m,p,k,mod;
int lx,ly;
int vis[505][505][22],iszombie[505][505][22];
char str[10];
struct ST{
	int x,y,t;
	ST(){}
	ST(int xx,int yy,int tt){
		x=xx,y=yy,t=tt;
	}
};
queue<ST>q;
int get_dir(char c){
	if(c=='R')return 0;
	if(c=='L')return 1;
	if(c=='U')return 3;
	if(c=='D')return 2;
}
void get_zombie(int num){
	int x,y;
	mod=2*(k-1);
	while(num--){
		scanf("%d%d",&x,&y);
		scanf("%s",str);
		x--,y--;
		int p=get_dir(str[0]);
		for(int t=0;t<=k-1;t++){
			int nowx=x+t*dir[p][0];
			int nowy=y+t*dir[p][1];
			iszombie[nowx][nowy][t]=1;
		//	printf("%d %d %d iszombie\n",nowx,nowy,t);
			iszombie[nowx][nowy][mod-t]=1;
		//	printf("%d %d %d iszombie\n",nowx,nowy,mod-t);
		} 
	}
	return ;
}
void get_point(){
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(map[i][j]=='L')q.push({i,j,0}),vis[i][j][0]=1;
			else if(map[i][j]=='A')lx=i,ly=j;
		}
	}
	return ;
}
int bfs(){
	while(q.empty()==0){
		ST tmp=q.front();
		q.pop();
	//	printf("q:%d %d %d\n",tmp.x,tmp.y,tmp.t);
		for(int i=0;i<=3;i++){
			int nowx=tmp.x+dir[i][0];
			int nowy=tmp.y+dir[i][1];
			int nowt=tmp.t+1;
			if(nowx<0||nowx>=n||nowy<0||nowy>=m)continue;
			if(map[nowx][nowy]=='&')continue;
			if(vis[nowx][nowy][nowt%mod]==1)continue;
			if(iszombie[nowx][nowy][nowt%mod]==1)continue;
			if(map[nowx][nowy]=='A')return nowt;
	//		printf("%d %d %d\n",nowx,nowy,nowt);
			vis[nowx][nowy][nowt%mod]=1;
			q.push({nowx,nowy,nowt});
		}
	}
	return -1;
}
int main(){
	scanf("%d%d%d%d",&n,&m,&p,&k);
	for(int i=0;i<n;i++){
		scanf("%s",map[i]);
	}
	get_zombie(p);
	get_point();
	int ans=bfs();
	if(ans==-1)printf("Oh no");
	else printf("%d",ans);
	return 0;
} 

H Hash

题目描述

这里有一个hash函数 const int LEN = 6;
int mod;
int Hash(char str[])
{
int res = 0;
for (int i = 0; i < LEN; i++)
{
res = (res * 26 + str[i] - ‘a’) % mod;
}
return res
}
现给定一个长度为 6 6 6的仅由小写字母构成的字符串 s s s和模数 m o d mod mod,请找到字典序最小且大于 s s s的一个长度为 6 6 6的仅由小写字母构成的字符串 s ′ s′ s,使得其 h a s h hash hash值和 s s s h a s h hash hash相等。

输入描述

多组用例,请处理到文件结束。(用例组数大约为1000组左右)对于每组用例,输入一行,包含一个长度为6的仅由小写字母构成的字符串 s s s和模数 m o d mod mod( 2 ≤ m o d ≤ 1 0 7 2≤mod≤10^7 2mod107),用空格隔开。

思路

将mod转换成26进制,字符串也转换成26进制,两者进行相加。再转换成字符串就可以了。

AC代码

#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define lb(x) x&(-x) 
#define maxn 100005
#define pi acos(-1)
char s[10];
int t1[10],t2[10];
ll mod;

void get(ll x){
 int i = 6;
 rep(j,0,6) t1[j] = 0; 
 while(x){
  t1[i--] = x%26;
  x /= 26;
 }
 rep(i,1,6)  t2[i] = s[i] - 'a';
}
void add(){
 int pos = 0;
 per(i,6,0){
  t1[i] += t2[i] + pos;
  pos = t1[i]/26;
  t1[i] %= 26;
 }
}
int main(){
    while(scanf("%s%lld",s+1,&mod) == 2){
     get(mod);
     add();
     if(t1[0]) printf("-1\n");
     else{
      rep(i,1,6) printf("%c",'a'+t1[i]);
      printf("\n");
     }
}
 return 0;
}

I I题是个签到题

题目描述

经过2019一年的比赛,牛牛战队的队员发现了一个重大规律:I题是个签到题!
签到题的定义是:通过人数大于等于全场人数的80%或者通过人数是所有题目前三多的题(也就是最多有两个题目通过人数严格比它多)叫做签到题。 2020赛季就要到了,牛牛战队要去验证这个规律了,已知现在每个题的过题情况,看一看I题是不是一个签到题。

输入描述

输入数据共2行。第一行包括两个整数 n , m n,m n,m( 9 ≤ n ≤ 13 , 100 ≤ m ≤ 1   000 9≤n≤13,100≤m≤1 000 9n13,100m1000),表示比赛的总题数和比赛的总人数。第二行包括以空格分隔的n个整数 a 1 , a 2 , ⋯   , a n ( a i > 0 ) a_1,a_2,⋯ ,a_n(a_i>0) a1,a2,,an(ai>0),表示每个题通过的人数。

AC代码

#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define lb(x) x&(-x) 
#define maxn 100005
#define mod 998244353
int n, m;
int a[100], num;
int main(){
 scanf("%d%d",&n,&m);
 rep(i,1,n) scanf("%d",&a[i]);
 rep(i,1,n) if(a[i] > a[9]) num++;
 if(a[9] >= (double)m*0.8 || num < 3) printf("Yes\n");
 else printf("No\n");
 
 
 return 0;
}

J 牛牛战队的秀场

题目描述

牛牛战队里,不仅有训练,也有追逐。 牛牛和牛能总是想知道谁更秀一点,他们通常会去比谁的代码更秀,谁的成绩更秀……
这一次,他们开始比谁的走位更秀。他们来到一个半径为 r r r的圆上,画了圆内接的正 n n n边形。为了秀走位,他们只允许自己在多边形的边上移动。 同时,他们随便选取正 n n n边形的一个顶点为1号顶点,按顺时针的顺序把其他的点叫做2号顶点,3号顶点……一开始,两人分别在iii号顶点和jjj号顶点。 现在,牛牛要一边沿着多边形的边秀走位,一边走向牛能。他想知道,他最短要走多少距离才能走到牛能的旁边?

输入描述

输入数据共2行,第一行有两个整数 n , r ( 3 ≤ n ≤ 1000 , 1 ≤ r ≤ 1 0 6 ) n,r(3≤n≤1000,1≤r≤10^6) n,r(3n1000,1r106),表示在半径为r的圆上画了一个内接n边形。第二行有两个整数 i , j ( 1 ≤ i , j ≤ n ) i,j(1≤i,j≤n) i,j(1i,jn),表示牛牛一开始在 i i i号顶点,牛能一开始在 j j j号顶点。

思路

实在不知道写什么,和上个题一样水。

AC代码

#include
using namespace std;
#define ll long long
#define rep(i,s,t) for(int i = s;i <= t;i++)
#define per(i,t,s) for(int i = t;i >= s;i--)
#define lb(x) x&(-x) 
#define maxn 100005
#define mod 998244353
#define pi acos(-1)
int main(){
    int n, r, i, j;
    scanf("%d%d",&n,&r);
    scanf("%d%d",&i,&j);
    int x = min(abs(i-j),n-abs(i-j));
    printf("%.6lf\n",2*x*r*sin(pi/n));
 return 0;
}

你可能感兴趣的:(2020牛客寒假算法基础训练营)