2020年1月2日新生赛002vj

这次只补了当时没做出来,比完赛之后会做了的题,大佬们太强了,蒟蒻的我真的巨弱…
比赛题目

A - 构造最长递增子串

本题不会,我看的孙大佬的题解,然后去学了dp,自己又写了一遍代码所以思路是完全一样的

题意:给定一段序列,选其中连续的一段(ai,ai+1…,aj),最多更改其中的一个数为任意值,使其变为递增子串。求这样的递增子串的最大长度。

解法:设两个数组,一个用来记录从1开始到i的满足连续递增序列的字串长度,另一个用来记录从n开始到i的满足连续递增序列的字串长度,更改当前ai的值判断能不能使ai两边的串连起来(不能则舍掉一边),更新最大长度

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int k=100010;
	int sum,x[k],y[k],a[k],n;//x[i]是用来记录从1开始到i的满足连续递增序列的字串长度,y[i]用来记录从n开始到i的满足连续递增序列的字串长度 
int main()
{

	while(scanf("%d",&n)!=EOF)
	{
	
	y[n+1]=sum=0;//这里必须每次清零,因为每次都会用到x[0],y[n+1],而且由于n每次变所以必须将y[n+1]归零 
		for(int i=1;i<=n;i++)
scanf("%d",&a[i]);//注意当有多组输入的时候别用cin,cout,我用了就超时了,之前问过学长这个问题,我才想起来 
	for(int i=1;i<=n;i++)
	{
		if(a[i]>a[i-1])
		x[i]=x[i-1]+1;
		else
		x[i]=1;//边界1 
		
	}
		for(int i=n;i!=0;i--)
	{
		if(a[i]<a[i+1])
		y[i]=y[i+1]+1;
		else
		y[i]=1;//边界2 
		
	}
	for(int i=1;i<=n;i++)
	{
		if(a[i+1]-a[i-1]>1)
		
			sum=max(sum,x[i-1]+y[i+1]+1);//状态转移方程,说明改个数两边能连起来 
		
		else
		sum=max(sum,max(x[i-1]+1,y[i+1]+1));//状态转移方程,后面那两个区间加一是因为,能改一次数(任意)  
	}
	cout<<sum<<endl;

	
 }
}

B - Is it beautiful?

这个题我读了好多遍都读懂,不大会,后来问的王锐同学,所以做法上可能也差不多,真的没想出来怎么做。

大意:给一个序列,并且从1开始然后1-2,1-i(1<=i<=n),直到1-n,若对应的输入序列中能找到对应的1-i(不用管顺序),则称对应的数为beautiful即那个位置输出1反之则输出0

解法:比如说输入 4 5 1 3 2 6,再定义个数组a为 1 2 3 4 5 6,按照输入的序列的大小从小到大排序,则序列变为 1 2 3 4 5 6,a变为3 5 4 1 2 6,此时序列变为连续序列了,意思就是1的位置为3,2的位置为5…,第一个数肯定满足要求,从第数组a的第二元素开始,那么如果1,2直接就为差值2-1=1则满足要求,但实际上对应序列中1和2之间(包括1不包括2)差的元素为5-3=2,2≠1所以不满足。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int k=200010;
struct o{
 int x;//为输入的序列中的数
 int y;//为(比如说为123456)在序列中对应的位置 
}a[k];
bool cmp(o a,o b)
{
 return a.x<b.x;
}
int main()
{   
 int t;
 scanf("%d",&t);
 while(t--)
 {
  int n,b[k]={0};
  cin>>n;
  for(int i=1;i<=n;i++)
  {
  cin>>a[i].x;
  a[i].y=i;
 }
  sort(a+1,a+1+n,cmp);
  int r=a[1].y,u=a[1].y;
  for(int i=2;i<=n;i++)
  {
   r=max(r,a[i].y);//不断的更新端点最大值和最小值
   u=min(u,a[i].y);
   if(r-u==i-1)//i-1即相隔的数
   b[i]=1;
   else
   b[i]=0;
   } 
   b[1]=1;
   for(int i=1;i<=n;i++)
   printf("%d",b[i]);
   printf("\n");
 }
}

C.Juicer

啃不动,以后再说

D - Eat Candies

题干:

You have
three piles of candies: red, green and blue candies:

the first pile contains only red candies and there are rr candies in it,
the second pile contains only green candies and there are gg candies in it,
the third pile contains only blue candies and there are bb candies in it.

Each day Tanya eats exactly two candies of different colors. She is free to choose the colors of eaten candies: the only restriction that she can’t eat two candies of the same color in a day.
Find the maximal number of days Tanya can eat candies? Each day she needs to eat exactly two candies.

Input
The first line contains integer tt (1≤t≤10001≤t≤1000) — the number of test cases in the input. Then tt test cases follow.
Each test case is given as a separate line of the input. It contains three integers rr, gg and bb (1≤r,g,b≤1081≤r,g,b≤108) — the number of red, green and blue candies, respectively.

Output
Print tt integers: the ii-th printed integer is the answer on the ii-th test case in the input.

Example
Input
6
1 1 1
1 2 1
4 1 1
7 4 10
8 1 4
8 2 8
Output
1
2
2
10
5
9

Note
In the first example, Tanya can eat candies for one day only. She can eat any pair of candies this day because all of them have different colors.
In the second example, Tanya can eat candies for two days. For example, she can eat red and green candies on the first day, and green and blue candies on the second day.
In the third example, Tanya can eat candies for two days. For example, she can eat red and green candies on the first day, and red and blue candies on the second day. Note, that two red candies will remain uneaten.

题意:

给定t组测试数据。
每组数据包含r,g,b三个数,代表3种糖的数量。
每天只能吃不同的两种糖,两种各吃一颗。
求最多能吃多少天。

解法:

比赛时想用优先队列做的,结果发现我想的有点太简单了,赛后看了看大佬的题解,所以这里可能有些雷同。。
由于红绿蓝的糖果的大小不知道所以我们可以假设:
r>g>b,设d=r-g
先一直吃最多的一堆和最小的一堆,这里设堆号按糖数从小到大排,设天数为day

若d≥b,则即使把最小的那堆都吃完了,最大的那堆也不会与第二堆糖数相等,一开始为b,g,r
此时堆里的糖为0,g,r-b,day=b,显然这里的第二堆还是比第三堆小,则易得此情况下day=b+g,

若d<b,先吃到第二堆与第三堆糖数相等此时为b-d,g,g,day=d,则第一堆仍有剩余,将其均分为两份,第一份与第二堆同时吃,第二份与第三堆同时吃。吃后第一堆糖数变为0即0,g-(b-d)/2,g-(b-d)/2,day=d+((b-d)/2)*2,然后后面就吃第二堆和第三堆了,day=day=d+b-d+g-(b-d)/2=(r+b+g)/2,除以二向下取整,那么奇偶的影响就被消除了。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{  int t,a[4],d,day;
  cin>>t;
  while(t--){
  day=0;
  for(int i=1;i<=3;i++)
   cin>>a[i];
   sort(a+1,a+4);
   d=a[3]-a[2];
   if(d>=a[1])
   day=a[2]+a[1];
   else
   day=(a[1]+a[2]+a[3])/2;
   cout<<day<<endl;
}
}
  

E - 由你来决定怎么颁奖

题意:

举行了一个比赛,颁奖有几个要求:金牌数的要比银牌数和铜牌数少,但银牌数和铜牌之间不需要有大小关系,且金牌数加银牌数加铜牌数小于2/n

解法
因为只要满足题目的要求就随便颁奖那么可以考虑极限的情况,金牌让他颁奖最少(只有得最高分得才能拿),让铜牌数最多,银牌数能满足条件就满足,不满足就算了

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int k=400010;
int a[k],t;
int main()
{
	cin>>t;
	while(t--)
	{
		int n;
		scanf("%d",&n);
		int mid=n/2;
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
		int g=0,s=0,b=0;
		int i=1;
		while(a[i]==a[1]&&i<=mid)//这里金牌数取个最容易想的,让它最小,就是只有为最高分才能得金牌  
		{
			i++;
			g++;
		}
		int x=a[i];
		while(a[i]==x&&i<=mid)
		{
			i++;
			s++;
		}
		while(s<=g&&i<=mid)//必须让在可能的情况下让金牌数小于银牌数 
		{
			int q=a[i];
			while(a[i]==q&&i<=mid)
			{
				i++;
				s++;
			}
		}
		int l=i,p=mid;//铜牌数我们也考虑极限情况就是只要比a[mid+1]大的且比因银牌数要求的最低分低的就能拿铜牌,如果满足金牌数小于铜牌数就输出反之则输三个0 
	int y=a[mid+1];//到mid+1因为g+s+b不能超过mid
	while(a[p]==y&&p>=l) //如果a[mid+1]前面就有与其值一样的那b也不能加了,因为不能相同的分一给给牌一个不给 
	{
		p--;
	}
	int o=a[p];
	while(p>=l&&a[p]>=o)
	{
		b++;
		p--;
	}
		if(g>=s||g>=b)
		printf("0 0 0\n");
		else
		printf("%d %d %d\n",g,s,b);
	}
	
	
	
}

F.XorXor

啃不动,以后再说

G - 0011

题干:

Alex likes to play with one and zero!One day he gets an empty string.So our cute boy wants to add one and zero in it. Every time he will add ‘01’in the string at any position and then get a new string.For example:if the string is “01” now ,he can get “0101” or “0011,Now give you a string that is Alex has get,you need to answer whether the string is legal?

Input
First is a integer n(n<=100)
Next contains n lines .Every line is a string whose legth is no more than 1000.

Output
For each case output “YES” in a single line if it’s legal.
Or you need to output “NO”;

Sample Input
3
0101
0110
0011

Sample Output
YES
NO
YES

解法:

看了下题解,大佬是设了个变量来记录0与1的出现来判断的,当时我没有想到这种好方法,我是用的String来做的,比较麻烦,通过每次查找有01的字符串,如果有就删掉,没有则直接输出“NO”,直到字符串的个数小于等于2。

代码:

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int main()
{
 int n;
 cin>>n;
 for(int i=1;i<=n;i++)
 {   int m,k,w=1;
  string str,a="01";
  cin>>str;
  while(str.length()>2)
  {
   m=str.find(a);
   if(m==string::npos)
   {
    w=0;
    cout<<"NO"<<endl;
    break;
   }
   else
   str.erase(m,2);
  }
  if(w==1)
  {
  k=str.find(a);
  if(k==string::npos)
  cout<<"NO"<<endl;
  else
  cout<<"YES"<<endl;
 }
 else
 continue;
 
 
}
}

H - Perfect String

题意:输入一个字符串,由’a’,‘b’,‘c’,’?‘组成,问能不能改’?’ 为’a’,‘b’,'c’中的一个,使该字符中任意一个字符的两侧均是不同的字符

解法:一个个找

代码:

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int main()
{
	int t,k;
	string a;
	cin>>t;
  for(int i=1;i<=t;i++)
  { k=0;
  	cin>>a;
  	if(a[0]=='?')
  	  {
  	  	if(a[1]!='a')
  	  	a[0]='a';
  	  	  else	if(a[1]!='b')
  	  	a[0]='b';
  	  	else	if(a[1]!='c')
  	  	a[0]='c';
		}
		for(int j=1;j<a.length();j++)
		{
			if(a[j]=='?')
			{
				if(a[j+1]!='a'&&a[j-1]!='a')
  	  	a[j]='a';
  	  	  else	if(a[j+1]!='b'&&a[j-1]!='b')
  	  	a[j]='b';
  	  	else	if(a[j+1]!='c'&&a[j-1]!='c')
  	  	a[j]='c';
			}
			if(a[j]==a[j+1]||a[j]==a[j-1])
			{
				k=1;
				break;
				
			}
		}
		if(k==1)
		cout<<-1<<endl;
		else
		cout<<a<<endl;
  }
}

I - 十进制中的二进制

题干:

hkhv学长最近对二进制数很感兴
趣,喜欢一切0和1组成的数。现在有一个十进制整数n,问你1到n之间有多少个数是只有0和1组成的类似二进制的数,输出他们的个数。

Input
输入数据包含一个数n (1 <= n <=10^9).
Output
输出1到n中类似二进制的数的个数.
Sample Input
10
Sample Output
2

Hint
对于n = 10,1 和 10是类似二进制的数.

解法:可以写几个数找找规律,1开始110=10,110+1=11,1010=100,1010+1=101,1110=110,1110+1=111,可以简单归纳,得到要求的这种数就是需要原数10或者原数10+1,dfs即可

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int ans,k;
void dfs(int a)
{
	if(a>k)
	{
		return;
	}
	if(a<=k&&a)
	ans++;
	dfs(a*10);
	dfs(a*10+1);
}
int main()
{
	while(scanf("%d",&k)!=EOF)
	{
		ans=0;
	dfs(1);
	cout<<ans<<endl;
}
 } 

J - 新年快乐

题干:

Frog Wa has many frogs, so he can hear GuaGuaGua every day. But one day a flappy bird ate his frogs, so Frog Wa decided to build a fence to protect his precious frogs. Frog Wa told you four points (x, 0), (x, y), (z, 0), (z, t) which represent for the vertex of the fence. he want to know the area of the fence, can you tell him?
Input
The input consist of four integers x, y, z and t. 0 <= x, y, z, t <= 10000, x < z and y < t.
Output
For each test case, print the area, numbers should accurate to one decimal places.
Sample Input
1 1 2 2
0 2 6 6
0 0 2 10
Sample Output
1.5
24.0
10.0

#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
 int x,y,z,t;
 double sum;
 while(scanf("%d%d%d%d",&x,&y,&z,&t)!=EOF)
 {
  sum=(z-x)*(y+t)*1.0/2.0;
  printf("%.1f\n",sum);
 }
 
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值