Codeforces Round #637 (Div. 2)

A 已知有n个数,他们的范围是[a-b,a+b],问这n个数(可以相等)的和是否能在[c-d,c+d]的范围内,直接判断即可。

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int t,n,m;
int main()
{
	cin>>t;
	while(t--)
	{
		int a,b,c,d;
		cin>>n>>a>>b>>c>>d;
		if((a+b)*n<(c-d)||(a-b)*n>(c+d)) puts("No");
		else puts("Yes");
	}
	return 0;
}

B 已知一个数组,如果a[i]>a[i-1]并且ai>a[i+1]那么ai就是一个山峰,如果在区间l[l,l+k-1]内有m个山峰,那么你的某种物品就被分成m+1份了,输出最大的m+1和区间起点l,如果有多个输出最小的l。预处理一下前面有多少个山峰,sum[i]就是前i个数的山峰数量(包括第i个数),这样区间内的山峰数量就可以计算了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=200010;
int t,n,m;
int a[N],sum[N];
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>n>>m;
		for(int i=1;i<=n;i++) cin>>a[i];
		int k=0,l=1;
		for(int i=2;i<=n;i++)
		{
			if(a[i]>a[i-1]&&a[i]>a[i+1]&&i<n) sum[i]=sum[i-2]+1;
			else sum[i]=sum[i-1];
			if(i>=m&&sum[i-1]-sum[i-m+1]+1>k)
			{
				l=i-m+1;
				k=sum[i-1]-sum[i-m+1]+1;
			}
		}
		cout<<k<<' '<<l<<endl;
	}
	return 0;
}

C 题意比较绕,读懂了就好理解了,按照题面意思生成随机数组,生成规则是:
第i步为数字i选择一个位置,选择依据是对于任意数字j(1<=j<=n)从第j个位置向后寻找第一个没有被占据的位置记为r[j],没有找到的不用管,最后统计所有数t(1<=t<=n)在r[]内出现的次数记为count[t],选择count[t]最大的数字t就是数字i的位置(如果有多个任意一个都可以)。

思路:假设n=7,i=1的时候count数组全为0,随意第一个,位置都可以任意选;假设选择5,接下来给2选位置,r数组: 1 2 3 4 6 6 7(第5个位置后第一个没被选的位置是6)count数组:1 1 1 1 0 2 1这时候只能选位置6;
然后选3的位置 r数组:1 2 3 4 7 7 7 ,count数组就是1 1 1 1 0 0 3,这时候就只能选位置7,
再给4选位置,r数组1 2 3 4 * * * (*)表示没找到rj,count数组:1 1 1 1 0 0 0 ,
这时候位置1到4都可以选,看第一步是不是很类似,令n=4就一模一样了;

对于n个数来说,1的位置可以任意选,假设选择t[1],选2的位置的时候 r数组除了t[1]的所有位置i都是i(r[i]=i,i!=t[1]),只有t[1]例外r[t[1]=t[1]+1,所以count数组中只有count[t[1]+1]=2,其他都是1或者0(count[t[1]]=0),所以2只能选择位置t[1]+1,3的位置也一样只能选择t[1]+2,所以t[1]往后都是递增的且差值等1,直到位置n被选择后,当前数可以选择t[1]之前的数,这时令n=t[1]-1,就是回到第一步的时候了。

所以对于随机数组ans,ans[i-1]<n的时候ans[i]必须等于ans[i-1]+1,当ans[i-1]==n时, 就可以选择前面的任意数了,相当于将全面的区间划分成连个,然后再后一个区间内一次递增,直到完全选择,然后再再前一个区间内划分继续一样的操作直到1到n的数全部出现。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=200010;
int t,n,m;
int a[N],sum[N];
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		int l=1,r=n,k=-1;初始区间是[1,n],k=-1表示要选择dl来划分区间了
		bool flag=1;
		for(int i=1;i<=n;i++)//当时想的复杂了一些,代码就繁琐了
		{
			if(k==-1)//该划分区间了
			{
				if(a[i]<l||a[i]>r)
				{
				 	flag=0;
				 	break;
				}
				else 
				{
					l=a[i];//这个时候就是dl
					if(l==r)//直接选择了区间最后一个点
					{
						l=1;
						r--;
					}
					else
						k=a[i]-1;//k保存dl-1
				}
			}
			else 
			{
				if(a[i]!=l+1) //划分过区间后就只能依次递增了
				{
					flag=0;
					break;
				}
				else 
				{
					l=a[i];
					if(l==r) //[dl,r]内的被选完了就缩小区间呗
					{
						r=k;//k=dl-1
						l=1;//区间左端点会一直是1直到结束了
						k=-1;//该划分区间了
					}
				}
			}
		}
		if(flag) puts("Yes");
		else puts("No");
	}
	return 0;
}

D待补,溜了溜了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值