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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章