Educational Codeforces Round 65 (Rated for Div. 2)

题目链接

A. Telephone Number

题目大意:给你一串数字,看能不能通过删除某些数字从而使这串数字变成一个电话号码。对电话号码的定义为8开头,长度为11位。

解题思路:找第一个8出现的位置,看到最后的长度有没有11位,如果有的话就输出YES,没有就输出NO。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		string s;
		cin>>n>>s;
		if(n < 11)
		{
			cout<<"NO"<<endl;
			continue;
		}
		else if(n == 11 && s[0] != '8')
		{
			cout<<"NO"<<endl;
			continue;
		}
		else
		{
			int pos = -1;
			for(int i=0;i<n;i++)
			{
				if(s[i] == '8')
				{
					pos = i;
					break;
				}
			}
			if(pos == -1 || n - pos < 11)
				cout<<"NO"<<endl;
			else
				cout<<"YES"<<endl;
		}
	}
	return 0;
} 

B.Lost Numbers

这个题就是有个交互,(快要被这个题搞死了写的时候), 写的时候一直WA on test 1 我还以为是我交互写错了。结果发现是题意理解错了,输入四次l,r 是返回的a[l] * a[r]。我还以为是 a[l] *a[l+1]....a[r]。结果浪费了好长时间 ,然后就根据题意模拟一下就行了。

#include<bits/stdc++.h>
using namespace std;
int a[7];
int b[7] = {0,4,8,15,16,23,42};
int main()
{
	for(int i=1;i<=4;i++)
	{
		if(i == 1)
			printf("? %d %d\n",1,3);
		else if(i == 2)
			printf("? %d %d\n",2,4);
		else if(i == 3)
			printf("? %d %d\n",3,5);
		else if(i == 4)
			printf("? %d %d\n",4,6);
		fflush(stdout);
		scanf("%d",&a[i]);
	}
	do
	{
		if(b[1]*b[3] != a[1])continue;
		if(b[2]*b[4] != a[2])continue;
		if(b[3]*b[5] != a[3])continue;
		if(b[4]*b[6] != a[4])continue;
		cout<<"!";
		for(int i=1;i<=6;i++)
			cout<<" "<<b[i];
		cout<<endl;
		exit(0);
	}while(next_permutation(b+1,b+6+1));
	return 0;
}

C.News Distribution 

题意就是给你n个点,m条边,让你求一下每个点的最大联通数。用并查集搞一搞就行了,

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
int fa[maxn];
int get(int x)
{
	if(x == fa[x])
		return x;
	return fa[x] = get(fa[x]);
}
void Union(int x,int y)
{
	fa[get(x)] = fa[get(y)];
}
int js[maxn];
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		fa[i] = i;
	for(int i=1;i<=m;i++)
	{
		int k;
		cin>>k;
		int t,pre;
		if(k == 0)continue;
		if(k == 1)
		{
			cin>>t;
			continue; 
		} 
		
		cin>>pre;
		for(int j=2;j<=k;j++)
		{
			cin>>t;
			if(get(t) == get(pre))continue;
			Union(t,pre);
			pre = t;	
		}	
	}
	for(int i=1;i<=n;i++)
	{
		js[get(i)]++;	
	}	
	for(int i=1;i<=n;i++)
		cout<<js[get(i)]<<" ";
	return 0;
}

D. Bicolored RBS

题目意思就是给你一堆括号。。 让你  mnimizes maximum of rr's and bb's nesting depth (就是两个串的深度差最小)。

题目思路:用贪心做就行了。。因为他保证给的括号是匹配的,所以对当前是左括号还是右括号分开处理就行了。左括号交替输出01,右括号交替输出01.然后这道题就做出来了。。 做出来我都感觉很懵逼。。

 

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a = 1;
	int b = 1;
	string s;
	int n;
	string a1 ="";
	string a2 = "";
	cin>>n>>s;
	for(int i=0;i<n;i++)
	{
		if(s[i] == '(')
		{
			if(a == 1)
				a1+=s[i];
			else
				a2+=s[i];
			cout<<a;
			a^=1;
		}
		if(s[i] == ')')
		{
			if(b == 1)
				a1+=s[i];
			else
				a2+=s[i];
			cout<<b;
			b^=1; 
		}
	}
	return 0;
}

E. Range Deleting

题目大意:给你n个点,这n个点中的最大值不超过x。定义一个f(l,r)操作为  删除这个数组a中所有 大于等于l 并且小于等于r的数。然后这个数组变成一个非严格单调递增的数组。 让你求这样的f(l,r)有多少个。。。定义空数组也算。

举个栗子:

3 3

2 3 1

样例输出:

4

表示这个数组a里有三个数  分别为 2,3,1. 这个数组中的最大值不超过3。

样例输出为4. 有f(1,1)  f(1,2)  f(1,3) f(2,3) 这四个。

f(1,1) 表示删除数组中所有的1  然后数组变成了 [2,3] 这个数组单调增

f(1,2)表示删除数组中所有 1,2 然后数组变成了[3] 这个数组单调增。

f(1,3)表示删除数组中所有 1,2,3 然后数组变成了[] 这个数组单调增。

f(2,3)表示删除数组中所有 2,3 然后数组变成了[1] 这个数组单调增。

解题思路:这个也是我看别人写的代码我才明白的。。我尽量叙述清楚一点。

如果删除 f(l,r)可以使数组有序,那么删除f(l,r+1)f(l,r+2) .... f(l,x)也是可以的。。

我们可以先找右边,使的删除f(l,r-1)为合法的, 然后再从小到大 遍历左端点.使的f(l+1,r-1)合法。。

我们需要四个数组

l[i] 记录数字i在数组中出现的最左边的位置

r[i]记录数字i在数组中出现的最右边的位置

ls[i] 记录大于等于数字 i的所有数 在数组中出现的最左边的位置. 例如数组a = [1,3,2] ls[2] = 2;因为3出现的位置是大于等于2中最左的

rs[i]记录小于等于数字i的所有数 在数组中出现的最右边的位置。数组a =[3,2,1] rs[2] = 3;因为1出现的位置是小于等于2中最右边的。

初始化R  = x;
然后我们先找到符合 ls[R]  >=  r[R-1]的最小数。也就是找到 任何大于等于R 的数的最左边出现的位置 要大于 R-1出现的最右端的位置。

然后我们开始枚举左端点。也就是满足 rs[i] <= ls[R]的所有左端点。。 跳出循环的条件就是 l[i] < rs[i-1] 也就是小于这个点的所有点的最右端点要比这个左边的i大了 。也就说明 f(l,r)无效了,因为有比l还小的数出现在r+1前面 。最后输出答案即可.

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e6+10;
int l[maxn],r[maxn];
int ls[maxn],rs[maxn];
int n,x;
int main()
{
	int d;
	cin>>n>>x;          
	memset(l,0x3f,sizeof(l));
	memset(ls,0x3f,sizeof(ls));
	for(int i=1;i<=n;i++)
	{
		cin>>d;
		l[d] = min(i,l[d]);         //第i个数出现的最小的位置 
		r[d] = i;                   //第i个数出现的最大的位置 
	}
	for(int i=1;i<=x;i++)
	{
		rs[i] = max(rs[i-1],r[i]); //小于等于i的数中  最右边的位置 
	}
	for(int i=x;i>=1;i--)
	{
		ls[i] = min(l[i],ls[i+1]);   //大于等于i的数中 最左边的位置 
	}
	LL ans = 0;
	int R = x;
	while(R >= 1 && r[R-1] <= ls[R])R--;
	for(int i=0;i<x;i++)
	{
		if(x != 0 && l[i] < rs[i-1])break;//表示以i为左边界已经不行了。
		while(R <= i+1 || rs[i] > ls[R])
		{
			R++;	
		}
		ans = ans + x - R + 2; 	
	} 
	cout<<ans<<endl;
	return 0;
} 

F. Scalar Queries 

G. Low Budget Inception

还没写 先咕咕 明天补。。。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值