牛客小白月赛3 (复盘)

A.音标

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

题目描述:
我们规定元音字母有a、e、i、o、u,并且规定半元音字母y也是元音字母。
Cwbc在学习英语,XHRlyb为了让Cwbc的记忆更加深刻,于是她让Cwbc把每个字符串的所有字母都变成一个恰好不大于它本身的小写元音字母。
可是Cwbc比较贪玩,并且他想让你帮他完成这个任务。
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输入描述:
输入数据有多行,每行有一个仅包含小写字母的字符串。
输出描述:
输出数据应有多行,每行有一个变化后的字符串。
备注:
每行字符串长度不超过2×105,字符串总长度不超过106

  • 题解:
  • 开局签到题,注意下是多组数据,用while套起来就行了。
#include<bits/stdc++.h>
using namespace std;
int main()
{
	string a;
	while(cin >> a)
	{
		for(int i=0;i<a.length();i++)
		{
			if(a[i]>='y')cout << "y";       /注意,y也要求在内
			else if(a[i]>='u')cout << "u";
			else if(a[i]>='o')cout << "o";
			else if(a[i]>='i')cout << "i";
			else if(a[i]>='e')cout << "e";
			else if(a[i]>='a')cout << "a";
		}	
		cout << endl;
	}	
	return 0;
} 

B.躲藏

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

题目描述:
XHRlyb和她的小伙伴Cwbc在玩捉迷藏游戏。
Cwbc藏在多个不区分大小写的字符串中。
好奇的XHRlyb想知道,在每个字符串中Cwbc作为子序列分别出现了多少次。
由于Cwbc可能出现的次数过多,你只需要输出每个答案对2000120420010122取模后的结果。
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输出描述:
输入数据有多行,每行有一个字符串。
输出描述:
输出数据应有多行,每行表示一个答案取模后的结果。
备注:
每行字符串长度不超过2×105,字符串总长度不超过106

  • 题解:
  • 简单的dp题目,设置dp[5]分别对应着 “cwbc” dp[0]不用
  • 然后遍历整个字符串, dp[ i ] 当前以第 i 位为结尾的前缀的出现次数
  • 例如:
  • 第一次:dp[1]只需计算c的个数就好了;
  • 第二次:dp[2]计算以“w”结尾,前面 “c” 的个数就好了;
  • 第三次:dp[3]计算以“b”结尾,前面 “cw” 的个数;
  • 第四次:dp[4]计算以“c”结尾,前面“cwb”的个数,全部累加起来,就是整个字符串中子序列为 “cwbc” 的个数了;
  • 注意: 题目里面有说明,是不区分大小写的
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 2000120420010122;     //定义要取模的常数
LL a[5];
int main()
{
	string s;
	while(cin >> s)
	{
		memset(a,0,sizeof(a));
		for(int i=0;i<s.length();i++)
		{
			a[1]=(a[1]+(s[i]=='c'||s[i]=='C'))%mod;
			a[2]=(a[2]+(s[i]=='w'||s[i]=='W')*a[1])%mod;
			a[3]=(a[3]+(s[i]=='b'||s[i]=='B')*a[2])%mod;
			a[4]=(a[4]+(s[i]=='c'||s[i]=='C')*a[3])%mod;
		}
		cout << a[4] << endl;
	}	
	return 0;
} 

C.博弈

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

输题目描述:
XHRlyb在和Cwbc玩游戏。
在一个多重集合中有在[l,r]中的全部整数各一个,即l,l+1,l+2,…,r。
每次XHRlyb和Cwbc可以选择一个大于0的数字p,把p从多重集合中删去,然后向集合中加入k个 p/k 的整数,最后不能操作的人算输。
如果博弈双方都是绝顶聪明的,并且XHRlyb先手,请你来帮XHRlyb预测这一局游戏谁会获胜。
如果博弈双方谁也无法取胜,那么判定为平局。
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输入描述:
输入数据有多行,每行有三个正整数,l,r,k。
输出描述:
输出数据应有多行,如果这一局XHRlyb获胜,那么请输出XHRlyb;如果Cwbc获胜,请输出Cwbc;如果两人平局,请输出Draw。
备注:
1 ≤ l ≤ r ≤ 105
1 ≤ k ≤ 100。
1 ≤ T ≤ 1000。

  • 题解:
  • 首先啦,他是要选择一个大于0的数才能继续,所以当这个 “p/k” 等于0的时候,这个数就不能被选择了;还有就是他是有k个“p/k”的数加进来。所以每次计算操作数的时候都要乘以k。
  • 我们设一个数要经历x次操作后,此数字不能再被操作,那么当这个x为奇数的时候,XHRlyb就能够获胜,反之,Cwbc获胜;
  • 还有就是特殊情况,当发现k=1的时候,“p/k”是无法消除的,所以这些数字只会越来越多,然后无法分出胜负。此时应该输出 “Draw”;
  • 因为对于同样的数据,操作数是固定的,所以这题我们可以进行初始化打表,计算出当k属于1 ≤ k ≤ 100。p属于1 ≤ l ≤ r ≤ 105时候的所有操作数。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 2000120420010122;
LL a[110][110000];
void init()
{
	LL k,s,p;
	for(k=2;k<=100;k++)
		for(p=1;p<=100000;p++)
		{
			s=p;
			while(s)
			{
				s=s/k;
				a[k][p]=a[k][p]*k+1;     //每次都会增加k个p/k,所以还要乘以k
			}
		}
}
int main()
{
	init();
	LL l,r,k;
	while(cin >> l >> r >> k)
	{
		if(k==1)
		{
			cout << "Draw" << endl;
			continue;
		}
		LL count = 0;
		for(LL i=l;i<=r;i++)
		{
			count+=a[k][i];
		}
		if(count%2!=0)cout << "XHRlyb" << endl;
		else cout << "Cwbc" << endl; 
	}
	return 0;
} 

D.妹纸

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

题目描述:
XHRlyb发明了一类数,叫做妹纸数。
假设xi∈[p,q],yi∈[u,v],且xi与yi均为整数,我们称这区间[p,q]相对于区间[u,v]的妹纸数为
i=p
∑ i mod v mod (v−1) mod … mod u
q
XHRlyb想让Cwbc帮她快速计算多组区间(a,b]相对于区间[l,r)的妹纸数。
Cwbc显然是愿意帮助她的,但他知道你不想解决这个问题,于是就把这个问题交给了你。
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输出描述:
输入数据有多行,每行有四个整数,a,b,l,r。
输入描述:
输出数据应有多行,每行有一个数,表示答案。
备注:
a ≤ b,l ≤ r。
a,b,l,r∈[1,106]。
1 ≤ 数据组数 ≤ 1000。

  • 题解:
  • 这题俺没有做出来,后面看了题解,做的时候题目意思理解错了,害。
  • 这个题目是计算区间和,但是也可以转化为计算前缀和来做。
  • 例如:假设我们需要求出 [4,8] 的区间和;我们可以先计算出4的前缀和,记:sum(4),再算出8的前缀和,记:sum(8),然后用sum(8)减去sum(4)就可以得到 [4,8]的区间和。
  • 显然我们也可以把这道题转化成这种形式,因为题中要求的区间为(a,b],所以我们可以先求出1–p对于区间[l,r)求余的和,在求出1–q区间[l,r)求余的和,然后做差即可。
  • 但是对于求1–p和1–q对于区间区间[l,r)求余的和是一个难题.
  • 再看细节,仔细看题,会发现,(a,b]区间是右开左闭,[l,r)区间是右闭左开;
  • 其实仔细想一想就能得出一个结论:一个数对于一个左闭右开的区间[l,r)求余的到的最大的数就是L-1。因为区间的不确定性,还分为两种情况:
  • 1.若x<r,则需要判断x%(r)与(L)的大小并求出最小值minn。在求1—minn的和。
  • 2.若x>=r,则直接算出1—L的和sum在乘以x/r,然后在加上情况1(因为x/r不一定被整除,不被整除的话x/r的余数正好符合情况1)
#include <iostream>
using namespace std;
typedef long long LL;
LL a,b,l,r;
LL Sum(LL n) //n的前缀和
{	
    return n*(n+1)/2;
}
LL solve(LL n) 
{
    return Sum(l)*(n/r)+Sum(min(n%r,l));
    //因为x<r的时候x/r等于0,所以可以把两种情况写到一起。
}
int main() 
{
    while (cin>>a>>b>>l>>r) 
    {
        l--,r--;
        //因为区间是左闭右开所以对于l求余的最大值即为l-1,r--是表示r能取到的最大值
        cout<<(solve(b)-solve(a))<<endl;
    }
    return 0;
}

F.异或

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

题目描述:
Cwbc想测试一下他的加密协议,以便防止其他人偷看他给XHRlyb的信。
Cwbc提出了这样一个问题:在区间[a,b]和区间[c,d]中分别等概率随机选择一个整数,两者异或之后等于0的概率是多少?
XHRlyb 一眼就看出了这个题目的答案,但她想让你计算一下这个概率。为了防止精度误差,你只需要输出一个形如a/b的最简分数。特别的,如果概率为0,你需要输出0/1。
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输入描述:
输入数据有多行,每行有四个非负整数a, b, c, d。
输出描述:
输出数据应有多行,每行有一个表示答案,形如x/y的最简分数。
备注:
a, b, c, d∈[0, 109]。
a ≤ b,c ≤ d
1 ≤ T ≤ 1000。

  • 题解:
  • 这题我感觉还是蛮简单的,签到题+1。
  • 首先我们要知道啥情况下,两个数异或为0,当两个数相等的时候,他们的异或值为0;
  • 所以,我们只要计算出两个区间内有几个相等的值就行了。
  • 最后就是对两个数进行一次约分,让其达到最简分数。输出就完事了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b)
{
	return b==0?a:gcd(b,a%b);
}
int main()
{
	LL a,b,c,d;
	while(cin >> a >> b >> c >> d)
	{
		if(c>b||d<a)   //当两个区间不想交时,直接返回0/1
		{
			cout << "0/1" << endl;
			continue;
		}
		LL min = (b<d?b:d)-(a>c?a:c)+1;   //计算出香蕉的值的个数
		LL max = (b-a+1)*(d-c+1);		//一共多少种组合
		LL g = gcd(min,max);			//计算出他们的最大公约数
		cout << min/g << "/" << max/g << endl; 
	}
	return 0;
}

G.旅游

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

题目描述:
Cwbc和XHRlyb生活在s市,这天他们打算一起出去旅游。
旅行地图上有n个城市,它们之间通过n-1条道路联通。
Cwbc和XHRlyb第一天会在s市住宿,并游览与它距离不超过1的所有城市,之后的每天会选择一个城市住宿,然后游览与它距离不超过1的所有城市。
他们不想住在一个已经浏览过的城市,又想尽可能多的延长旅行时间。
XHRlyb想知道她与Cwbc最多能度过多少天的时光呢?
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输入描述:
第一行,两个正整数n和s,表示城市个数和第一天住宿的城市s。
接下来n-1行,每行两个整数x和y,表示城市x与城市y之间有一条双向道路。
输出描述:
第一行,一个非负整数表示答案。
备注:
1 ≤ n ≤ 500000, 1 ≤ s, x, y ≤ n。

  • 无题解
  • 这是个经典的树形dp问题,可惜我还没练习到这里来,害。
  • 等我以后搞完再回来修改吧!先贴个ac代码。
#include<bits/stdc++.h>
#define maxn 1000000
using namespace std;
int n,f[maxn][2],s;
int point[maxn],nxt[maxn],head[maxn],tot;

void add(int x,int y){
    point[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}

void dp(int u,int fa){
    for(int i=head[u];i;i=nxt[i])
	{
        int v=point[i];
        if(v==fa)continue;
        dp(v,u);
        f[u][0]+=max(f[v][1],f[v][0]);
        f[u][1]+=f[v][0];
    }
}

int main()
{
    scanf("%d%d",&n,&s);
    for(int i=1;i<=n;i++)f[i][1]=1;
    for(int i=1,x,y;i<=n-1;i++) 
    {
    	scanf("%d%d",&x,&y);
    	add(y,x);
    	add(x,y);  //双向图
    }
   
    dp(s,0);
   
    printf("%d",f[s][1]);
   
    return 0;
}

H.纪年

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

题目描述:
Cwbc和XHRlyb在学习干支纪年法。
干支纪年法是中国历法上自古以来就一直使用的纪年方法。干支是天干和地支的总称。甲、乙、丙、丁、戊、己、庚、辛、壬、癸等十个符号叫天干;子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥等十二个符号叫地支。
为了方便程序的书写,我们不妨将天干记做1到10,地支记做1到12。
通过查阅日历,Cwbc知道农历2018年是戊戌年,XHRlyb想知道农历的n年是什么年。
0年指1年的前一年。
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输入描述:
输入数据有多组数据,每行有一个整数,表示n。
输入描述:
输出数据应有多行,每行两个整数,分别表示天干和地支的编号。
备注:
n ∈ [0, 1018]。
1 ≤ T ≤ 1000。

  • 题解:
  • 咳咳,这个说实话,不了解天干地支的朋友,怎么做也做不出来的。
  • 首先我们来了解一下这个天干地支到底是个什么情况哈!
  • 我们一般都是尾数定天干,余数定干支。
尾数定天干
4567890123
余数定地支
45678910110123
  • 例如,2018年,尾数为8,对应的就是 “戊” ;对12取余为2,对应的就是 “戌” ,所以2018年就是 “戊戌年”。
  • 现在我们将其变成从1开始,那么甲是4,将其变成第1位的话就是减3;其余的同理;
  • 当后面出现小于或等于0的时候,我们将其加上一个周期变为正数即可!
  • 所以,这题得到结论:
  • 天干:年份除以10,得到余数;余数减3;结果对应的天干的第几位;小于或等于0的情况后,给其加上一个循环周期;
  • 地支:年份除以12,得到余数;余数减3;结果对应的地支的第几位;小于或等于0的情况后,给其加上一个循环周期;
#include<bits/stdc++.h> 
using namespace std;

/*
		天干:年份除以10,得到余数;余数减3;结果对应的天干的第几位;
		地支:年份除以12,得到余数;余数减3;结果对应的地支的第几位;
*/

int main()
{
	long long  n,a,b;
	while(cin >> n)
	{
		a=n%10-3;
		b=n%12-3;
		if(a<=0)a+=10;
		if(b<=0)b+=12;
		cout << a << " " << b << endl;
	}	
	return 0;
}

I.排名

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

题目描述:
Cwbc和XHRlyb都参加了SDOI2018,他们特别关心自己的排名。
我们定义每一场比赛每位选手的标准分为它的分数乘以满分再除以比赛中选手所获得的最高分。
NOIP2017的满分为600分,SDOI2018每一天的比赛满分均为300分。
我们定义总分为NOIP2017的标准分的25%,加上SDOI2018 前两天标准分之和的25%,再加上SDOI2018后两天标准分之和的50%。
XHRlyb告诉你每一次比赛每个选手的分数,你需要按照名次从高到低依次输出他们的名字和总分。
聪明的你在仔细阅读题目后,一定可以顺利的解决这个问题!
输出描述:
输入数据有多组数据,对于每组数据,格式为:
第一行,一个整数n,表示选手数量。
接下来n行,每一行有用空格隔开的一个字符串和五个整数,分别表示选手姓名、NOIP2017成绩以及SDOI2018四天比赛的成绩。
输入描述:
输出数据应有多组,每组输出有多行,每行应有一个选手姓名和他的总分。
输出的总分应保留5位小数,且如果总分的误差不超过10-5,我们认为两名选手并列。
若两名选手并列,则按姓名的字典序顺序从小到大输出。
备注:
保证姓名均为小写字母且个数在[2,10]之间,每次比赛的分数不会超过满分也不会低于0分。
保证选手总数不会超过2 ∗ 105
1 ≤ T ≤ 5。

  • 备注:
  • 这题看起来很复杂,其实这是一个水题,害。
  • 首先我们直接搞一个结构体,将名字,n天的成绩,以及总分命名好;
  • 然后在输入值的时候,用maxs数组记住n天里面,每天的最高成绩,作为标准分的一个计算指标;
  • 然后就是排序,先按分数排序,从大到小降序,如果分数相等就按名字的字典序,小的在后面;然后输出就行了,总分里面保留五位小数。
#include<bits/stdc++.h>
using namespace std;
struct node
{
	string name;				//名字
	double b[5];				//每天的成绩
	double s;					//待计算的总分成绩,方便排序
}a[510000];
double maxs[5];
int cmp(struct node a,struct node b)	//对结构体进行排序
{
	if(a.s!=b.s)return a.s>b.s;			//先按照总分排序,从大到小
	else return a.name<b.name;			//如果分数相等,按照名字字典序排序,从小到大
}
int main()
{
	int n;
	while(cin >> n)
	{
		for(int i=0;i<5;i++)maxs[i]=0;
		for(int i=0;i<n;i++)
		{
			cin >> a[i].name;
			cin >> a[i].b[0] >> a[i].b[1] >> a[i].b[2] >> a[i].b[3] >> a[i].b[4];
			maxs[0]=max(maxs[0],a[i].b[0]);			//记录每天最好的成绩
			maxs[1]=max(maxs[1],a[i].b[1]); 		//作为标准分的最高分指标
			maxs[2]=max(maxs[2],a[i].b[2]); 
			maxs[3]=max(maxs[3],a[i].b[3]); 
			maxs[4]=max(maxs[4],a[i].b[4]); 
		}
		
		for(int i=0;i<n;i++)   //计算出每个人的总分
		{
			a[i].s=a[i].b[0]*600/maxs[0]*0.25;   						
			//2017占25%
			
			a[i].s+=(a[i].b[1]*300/maxs[1]+a[i].b[2]*300/maxs[2])*0.25;	
			//2018前两天占25%
			
			a[i].s+=(a[i].b[3]*300/maxs[3]+a[i].b[4]*300/maxs[4])*0.5;	
			//2018后两天占50%
		}
		
		sort(a,a+n,cmp);		//进行结构体排序,c++自带的快速自定义排序
				
		for(int i=0;i<n;i++)	//按照题目意思,输出即可
		{
			cout << a[i].name << " ";
			printf("%.5lf\n",a[i].s);
		}
	}
	
	return 0;
} 
  • 然后今天的小白就到这吧,后面的慢慢来。
改革尚未成功,同志仍需努力!!!
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木不会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值