Educational Codeforces Round 148 (Rated for Div. 2) A-D 题解

比赛地址

A. New Palindrome

题意:给一个回文串,判断是否能重新排成另一个回文串

Solution

存不同对的个数即可

void solve()
{
	string s;
	cin>>s;
	int n=s.length();
	set<char>st;
	for(int i=0;i<n/2;i++)
	{
		st.insert(s[i]);
	}
	if(st.size()>1)cout<<"YES\n";
	else cout<<"NO\n";
}

B. Maximum Sum

题意:给出一个数组,进行k次操作,每次操作选择最大的一个数或者最小的两个数删掉,求最后的数组和最大值

Solution

枚举删掉最小数的次数和删掉最大数的次数,然后答案取大即可

不是每次找最小的,有误导性

void solve()
{
	int n,k;cin>>n>>k;
	p[0]=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		
	}
	sort(a+1,a+1+n);
	for(int i=1;i<=n;i++)
	{
		p[i]=p[i-1]+a[i];
	//	cout<<p[i]<<" ";
	}
	int ans=0;
	//cout<<"\n";
	for(int i=0;i<=k;i++)
	{
		int l=i*2+1,r=n-(k-i);
	//cout<<l<<" "<<r<<" "<<p[r]-p[l-1]<<"\n";
		ans=max(ans,p[r]-p[l-1]);
	}
	cout<<ans<<"\n";
}

C. Contrast Value

题意:给出一个数组,求它的子数组,满足子数组相邻数的差的绝对值之和等于原数组相邻数的差的绝对值之和

Solution

对于连续的三个数a,b,c,如果满足a<=b<=c或者a>=b>=c,我们才能把b删掉,于是答案就变成了找单调区间(找谷峰的个数)

原AC代码

void solve()
{
	int n;cin>>n;
	set<int>p;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		p.insert(a[i]);
	}
	if(p.size()==1)
	{
		cout<<"1\n";
		return;
	}
	int pos=0;
	set<int>st;
	int last=-1;
	int flag=0;
	for(int i=1;i<=n;i++)
	{
		if(last==-1)
		{
			last=a[i];
			st.insert(i);
		}else
		{
			if(flag==0)
			{
				if(a[i]>last)
				{
					flag=1;
					last=a[i];
				}else if(a[i]<last)
				{
					flag=-1;
					last=a[i];
				}
			}else if(flag==-1)
			{
				if(a[i]<=last)
				{
					last=a[i];
				}else
				{
					st.insert(i-1);
					
					last=a[i];
					flag=1;
				}
			}else
			{
				if(a[i]>=last)
				{
					last=a[i];
				}else
				{
					st.insert(i-1);
					
					last=a[i];
					flag=-1;
				}
			}
		}
		//cout<<st.size()<<"\n";
	}
	st.insert(n);
	//for(auto it:st)cout<<it<<" ";
	//cout<<"\n";
	cout<<st.size()<<"\n";
}

找谷峰AC代码

// Problem: C. Contrast Value
// Contest: Codeforces - Educational Codeforces Round 148 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1832/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define int long long
//#define INF 0x3f3f3f3f3f3f3f3f
#define INF 0x3f3f3f3f
#define FOR(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
int lowbit(int x) { return -x & x; } 
const int mod = 998244353;
//const int mod = 1e9 + 7;
const int N = 1e6 + 10;
const int M = 6e5 + 5;
int ksm(int x, int y, int mod1 = mod) {  
    int res = 1;
    x %= mod1;
    while (y > 0) {
        if (y & 1)
        {
            res = res * x % mod1;
        }
        y >>= 1;
        x = (x * x) % mod1;
    }
    return res;
}
int gcd(int a, int b)    
{
    return b ? gcd(b, a % b) : a;
}
int lcm(int a, int b)    
{
    return a / gcd(a, b) * b;
}
typedef pair<int, int> pii;

int a[N];
void solve()
{
	int n;cin>>n;
	set<int>p;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		p.insert(a[i]);
	}
	if(p.size()==1)
	{
		cout<<"1\n";
		return;
	}

	int last=-1;
	int ans=0;
	
	for(int i=1;i<=n;i++)
	{
		int j=i;
		while(j+1<=n&&a[j+1]==a[i])j++;
		if(j+1<=n)
		{
			if(a[j+1]>=a[j])while(j+1<=n&&a[j+1]>=a[j])j++;
			else while(j+1<=n&&a[j+1]<=a[j])j++;
			ans++;
			i=j-1;
		}else break;
	}
	cout<<ans+1<<"\n";
}
signed main(void) 
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
    int t = 1;
    cin>>t;
    while (t--)
    {
        solve();
    }
    return 0;
}


D. Red-Blue Operations

题意:给出一个数组,初始全为红色,进行q次查询,每次查询会进行k次操作

第i次操作任选一个数

如果它是红色,则染成蓝色,并且+i

反之如果蓝色,则染成红色,并且-i

问每次查询最小值最大是多少

Solution

很难调啊,调了一个多小时

考虑到查询求最小值的最大值,那么我们用二分来判断

首先找到所有比mid小的数,找到后,其实我们可以从小到大给数组里的数依次加上k,k-1,k-2,...

如果比mid小的数个数比k还大,说明一定无法让所有数大于等于mid

如果所有数都比mid小,考虑到已经从小到大依次加上了对应的数,此时所有的数都为蓝色,如果剩余操作次数为奇数,则代表一定会有一个数比最开始还要小,如果剩余操作次数为偶数,可以将成对的操作数如[1,2],[3,4]给到同一个数上,这样只会使得该数-1,于是我们算一下操作后的所有数的和,减去mid*n,将其与剩余操作次数left/2比较即可

如果部分数比mid小,那么首先我们处理出同上述操作后剩余的操作次数,即 k-给数组依次加上k,k-1,...所需要的操作次数-(操作后所有数的和-mid*cnt),令其为res

如果res<=0,则可以满足

如果res是奇数,那么对于剩余那些已经比mid大的数随便挑一个,让其进行剩下res次操作,一定会变大

如果res是偶数

先判断剩下已经比mid大的数的个数,如果个数>=2,则可以先通过一次操作将其变为奇数,接下来选另一个数进行剩下的操作

如果个数=1,则需要判断一下在进行了操作之后会不会使得这个数比mid小即可

int check(int mid)
{
	int p=lower_bound(a+1,a+1+n,mid)-a;
	//cout<<mid<<" "<<p<<"\n";
	if(p-1==0)return 1;
	//cout<<mid<<"\n";
	if(p-1>k)return 0;
	if(p>n&&(k-n)&1)return 0;
	//cout<<mid<<"\n";
	if(t[p-1]+k<mid)return 0;
	//cout<<mid<<"\n";
	if(p>n&&(k-n)%2==0)
	{
		int left=k-(p-1);
		//cout<<s[p-1]<<"\n";
		return (s[p-1]+(k-mid)*(p-1))*2>=left;
	}
	//cout<<mid<<"\n";
	int left=k-(p-1)-(s[p-1]+(k-mid)*(p-1))*2;
	if(left<=0||left&1)return 1;
	if(n-(p-1)>=2)return 1;
	if(a[n]-left/2>=mid)return 1;
	return 0;
	
}


void solve()
{
	cin>>n>>q;
	for(int i=1;i<=n;i++)cin>>a[i];
	sort(a+1,a+1+n);
	
	t[1]=a[1];
	s[1]=t[1];
	for(int i=2;i<=n;i++)
	{
		t[i]=min(t[i-1],a[i]-(i-1));
		s[i]=s[i-1]+a[i]-(i-1);
	}
	while(q--)
	{
		cin>>k;
		if(n==1)
		{
			if(k&1)cout<<a[1]+k-(k-1)/2<<"\n";
			else cout<<a[1]-(k/2)<<"\n";
			continue;
		}
		int l=1,r=1e18;
		while(l<r)
		{
			int mid=(l+r+1)>>1;
			if(check(mid))l=mid;
			else r=mid-1;
		}
		cout<<l<<" ";
	}
}
posted @   HikariFears  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示