Codeforces Round #616 (Div. 2) A-C

A Even But Not Even
链接:http://codeforces.com/contest/1291/problem/A
题意 :给你一个数字 删去任意数字(可以不删)后 使得这个数字是奇数 各个位数和是偶数(不包含前导0)
思路:开个数组保存前缀和 向后遍历 标记一个前面的奇数 如果遍历到某一位后 这位数是奇数 前缀和是偶数 那么全部输出 如果前缀和是奇数 把标记的奇数删除
听说了一个思路 找两个奇数 就好了 tql

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
 
int main()
{
	int t,n;
	char s[N];
	cin>>t;
	while(t--)
	{
		cin>>n>>s+1;
		int sum[N];
		sum[0]=0;
		int j=-1;
		bool flag=0,flag1=0;
		for(int i=1;i<=n;i++)
		{
			sum[i]=sum[i-1]+s[i]-'0';
			
			if(j!=-1&&sum[i]&1&&(s[i]-'0')&1)
			{
				n=i;
				flag=flag1=1;
				break;
			}
			if(sum[i]%2==0&&(s[i]-'0')&1)
			{
				n=i;
				flag=1;
				break;
			}
			if(j==-1&&(s[i]-'0')&1)j=i;
		} 
		if(flag)
		{
			if(flag1)
				for(int i=1;i<=n;i++)
					if(j==i) continue;
					else
						cout<<s[i];
			else 
				for(int i=1;i<=n;i++)
						cout<<s[i];
			cout<<endl;
		}
		else cout<<-1<<endl;
	}
	return 0;
}

B. Array Sharpening
链接:http://codeforces.com/contest/1291/problem/B
说起b题就是一把伤心泪啊 先是看错题意 发现错了后又东改西改 越改越乱 哎还是太菜了
题意给你一个数组 你可以选择任意一个正数把它-1 (任意次 只要是正数)
问你是否可以把它变成一个前半部单调递增后半部单调递减的数组 (单调递增,单调递减也都可以)
从前向后遍历 cnt保存前部分有多少个负数 那么 下标为cnt+1的地方就是0出现的位置 那么 第i位置的最小值就是 i-cnt -1 找到不满足的地方 保存为l。l-1就是前半部分最长的单增长度 同理 从后向前遍历找到最大的单减位置是r+1 如果 l-1>=r+1 即
l>=r+2就是两段区间有交集 就符合题意了 还有如果 l或者r没有更新过那么就是可以变成一个完全单调的数组。满足三者中的一个就可以了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=300010;
 
int main()
{





	int t,n;
	int s[N];
	s[0]=-1;
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++)
			cin>>s[i];
		int l=0,r=n+1,t,cnt=0;
		for(int i=1;i<=n;i++)
		{
			if(i==1) 
			{
				if(s[1]<0) cnt++;
				continue;
			}
			if((s[i]>0&&s[i]<i-cnt-1)||(s[i]<=0&&s[i]<=s[i-1])) 
			{
				l=i;
				break;
			}
			if(s[i]<0&&s[i]>s[i-1])
				cnt++;
		}
		cnt=0;
		for(int i=n;i>0;i--)
		{
			if(i==n)
			{
				if(s[i]<0) cnt++;
				 continue; 
			 }
			if((s[i]>=0&&s[i]<n-i-cnt)||(s[i]<=0&&s[i]<=s[i+1]))
			{
				r=i;
				break;
			}
			if(s[i]<0&&s[i]>s[i+1])
				cnt++;
		}
		if(!l||r==n+1||l>r+1) cout<<"Yes"<<endl;//区间[1,l-1]与区间[r+1,n]有交集
		else cout<<"No"<<endl;
	}
	
	return 0;
}

C :http://codeforces.com/contest/1291/problem/C
题意:共有n个数字 m个人 每个人可以从数组序列的头部或者尾部拿走一个数字 你是第m个 但是你有个特权可以指定前k个人拿那些数,问在这样的条件下你一定能拿到的数的最小值(就是说你拿到的数一定比它大,使这个数最大化)

观察之后会发现前k个人指定后 剩余的数字的长度是不变且连续的 就是
区间[1,n-k] ->区间 [ k+1,n] 这些个区间就是指定后k后剩余的所有情况了
每个区间先求最小值 再在这些值中求最大值
那么问题就是每个区间阿怎么求最值了
现在就要分两种情况 如果 m < k 那么就要在这些区间上随机的选m-k 次了
假设在区间[l,r]上选k次那么前k-1次选择后剩下的数字还是长度不变且连续的区间了
区间[l,r-k+1] -> [l+k,r] 枚举每个区间 在区间两端取最大的那一个 在这几个区间内取最小值 就在区间[l,r] 上取k次的最小值了
然后 如果 m>=k 那么就不用指定k个人了 只用指定 m-1个 所以把上的 k 换成m-1就行了 就是在枚举的区间内都取一次

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3560;
int t,n,m,k,s[N];
int check(int l,int r,int k)在区间[l,r]内取k次取得的最小值
{
	int res=0x3f3f3f3f;
	for(int i=l;i<l+k;i++)
		res=min(res,max(s[i],s[i+r-l-k+1]));每个区间两端取最大值 所有区间取最小值
	return res;
}
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>n>>m>>k;
		int ans=0;
		for(int i=0;i<n;i++)
			cin>>s[i];
		if(m>k)
			for(int i=0;i<=k;i++)
				ans=max(ans,check(i,n-k+i-1,m-k));
		else
			for(int i=0;i<=m-1;i++)
				ans=max(ans,check(i,n-m+i,1));
		cout<<ans<<endl;
	}
	return 0;
}
发布了26 篇原创文章 · 获赞 3 · 访问量 614

猜你喜欢

转载自blog.csdn.net/qq_45288870/article/details/104158773