Codeforces Round #637 (Div. 2) (A~D)题解

A.Nastya and Rice

题意:
给你五个数 n , a , b , c , d n,a,b,c,d n,a,b,c,d.
表示让你找出 n n n个数,每个数的范围是 [ a − b , a + b ] [a-b,a+b] [ab,a+b],问能不能找出这样一个数组,使得总和在 [ c − d , c + d ] [c-d,c+d] [cd,c+d].
题解:
判断一下 n n n个最大值的和是否小于 c − d c-d cd, n n n个最小值的和是否大于 c + d c+d c+d即可

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
int t,n,a,b,c,d;
void solve(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d%d%d",&n,&a,&b,&c,&d);
		if(n*(a-b)>(c+d)||n*(a+b)<(c-d)) printf("No\n");
		else printf("Yes\n");
	}
}
int main(void)
{
	solve();
	return 0;
}

B.Nastya and Door

题意:
给定一个长度为n的数组,让你找出一个长度为k的子数组,这个子数组的山峰的数量最多,满足 a [ i − 1 ] < a [ i ] , a [ i ] > a [ i + 1 ] a[i-1]<a[i],a[i]>a[i+1] a[i1]<a[i],a[i]>a[i+1]的i即为山峰,输出最小的左端点的值.
题解:
先预处理出关于山峰数量的前缀和,然后暴力即可

#include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
const int MAX = 2e5+5;
const int INF = 0x3f3f3f3f;
int t,n,k,a[MAX],sum[MAX],mx,mj;
bool vis[MAX];
void solve(){
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&k);
		mx=-INF;
		for(int i=1;i<=n;++i) vis[i]=false,sum[i]=0;
		for(int i=1;i<=n;++i) scanf("%d",&a[i]);
		for(int i=2;i<n;++i) if(a[i]>a[i-1]&&a[i]>a[i+1]) vis[i]=true;
		for(int i=1;i<=n;++i) sum[i]=vis[i]+sum[i-1];
		for(int i=1;i<=n-k+1;++i){
			int num = max(0,sum[i+k-2]-sum[i]);
			if(num+1>mx) mx=num+1,mj=i;
		}
		printf("%d %d\n",mx,mj);
	}
}
int main(void)
{
	solve();
	return 0;
}

C.Nastya and Strange Generator

题意:
给定一个长度为n的排列,问经过题目中给出的算法流程,能否生成这样的排列.
算法流程为:
假定给出一个 [ 2 , 3 , x , x , 1 ] [2,3,x,x,1] [2,3,x,x,1].下一步的话就是要计算出4填入的位置
计算出r数组为 [ 3 , 3 , 3 , 4 , x ] [3,3,3,4,x] [3,3,3,4,x]. r数组的意义为当前节点开始往右数第一个未知元素的位置
然后计算出count数组 [ 0 , 0 , 3 , 1 , 0 ] [0,0,3,1,0] [0,0,3,1,0], count数组的意义为r数组中数字的个数.
然后现在count最大值的位置是3,所以往原数组3这个位置填入4,假如有多个最大值,则任意选择一个.

题解:
其实看样例都可以看出来规律了.
当填入数字 i + 1 i+1 i+1时,当这个数组形如 [ x , x , x , 1 , 2.. i ] [x,x,x,1,2..i] [x,x,x,1,2..i]这样填入的和未填入的位置没有交错时,数字 i + 1 i+1 i+1可以任意填入一个位置.
反之,只能填入 p o s [ i ] + 1 pos[i]+1 pos[i]+1的位置, p o s [ i ] pos[i] pos[i]为数字i所在的位置.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e5+5;
const int INF = 0x3f3f3f3f;
int t,n,a[MAX],mx[MAX],idx[MAX];
bool flag;
void solve(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);flag=true;
		for(int i=1;i<=n;++i) scanf("%d",&a[i]),idx[a[i]]=i;
		for(int i=n;i>=1;--i) mx[i]=max(mx[i+1],a[i]);
		for(int i=1;i<=n;++i){
			if(mx[idx[i]]==i) continue;
			else if(idx[i]+1==idx[i+1]) continue;
			else{ flag=false;break; }
		}
		for(int i=1;i<=n;++i) mx[i]=0;
		printf("%s",flag?"Yes\n":"No\n");
	}
}
int main(void)
{
	solve();
	return 0;
}

D.Nastya and Scoreboard

题意:
给你n段数码管,然后让你再点亮 k k k个数码位,问最大数字是多少
题解:
c n t [ i ] [ j ] cnt[i][j] cnt[i][j]代表i这个数到数字j需要点亮多少个数码位.
直接dfs爆搜.
从第一个数码管开始遍历,每个数码管枚举 9 − 0 9-0 90.
但是这样会超时,需要加上一点剪枝.
需要记录一个 v i s vis vis数组, v i s [ i ] [ j ] vis[i][j] vis[i][j]表示第i个数码管剩下j次操作是否可行,不可行则为 f a l s e false false.
每次 d f s dfs dfs记录一下当前还剩下多少次操作即可

#include<bits/stdc++.h>
using namespace std;
const int MAX = 1e4+5;
const int INF = 0x3f3f3f3f;
string s[10]={ "1110111", "0010010", "1011101", "1011011", "0111010", "1101011", "1101111", "1010010", "1111111", "1111011"};
string lis[MAX],ans="",temp="";
bool vis[2005][2005];
int a[8],cnt[MAX][10],n,k;
void init(int index){
	if(index==7){
		int num=0;
		for(int i=6,j=0;i>=0;--i,++j) num+=a[i]*(1<<j);
		for(int i=0;i<=9;++i){
			int count=0;
			bool flag=true;
			for(int j=0;j<7;++j){
				if(a[j]==1&&s[i][j]=='0'){
					cnt[num][i]=INF;
					flag=false;
					break;
				}
				else if(a[j]==0&&s[i][j]=='1'){
					++count;
				}
			}
			if(flag){
				cnt[num][i]=count;
			}
		}
		return;
	}
	a[index]=0;
	init(index+1);
	a[index]=1;
	init(index+1);
}
bool dfs(int index,int k){
	if(ans!="") return true;
	if(index==n){
		if(k!=0) return false;
		for(int i=0;i<n;++i) ans+=temp[i];
		return true;
	}
	if(!vis[index][k]) return false;
	int num=0;
	for(int i=6,j=0;i>=0;--i,++j) num+=(lis[index][i]-'0')*(1<<j);
	bool f=false;
	for(int i=9;i>=0;--i){
		temp[index]=(char)(i+'0');
		if(cnt[num][i]==INF||cnt[num][i]>k) continue;
		bool v=dfs(index+1,k-cnt[num][i]);
		vis[index+1][k-cnt[num][i]]=v;
		if(v) f=true;
	}
	return f;
}
void solve(){
	init(0);
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;++i) temp+="0";
	for(int i=0;i<=2000;++i)
		for(int j=0;j<=2000;++j)
			vis[i][j]=true;
	for(int i=0;i<n;++i) cin>>lis[i];
	dfs(0,k);
	if(ans=="") ans="-1";
	cout<<ans;
}
int main(void)
{
	solve();
	return 0;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值