首页 > 其他分享 >Educational Codeforces Round 148 (Rated for Div. 2) A-D 题解

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

时间:2023-05-13 11:22:23浏览次数:55  
标签:Educational Rated return cout int 题解 mid res 操作

比赛地址

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<<" ";
	}
}

标签:Educational,Rated,return,cout,int,题解,mid,res,操作
From: https://www.cnblogs.com/HikariFears/p/17396995.html

相关文章

  • 「SDOI2017」数字表格 题解
    4114「SDOI2017」数字表格题解个人评价:好题且套路多算法标签莫比乌斯反演题目难度:2700题面看我分析题面多组数据,每次给出\(n,m\),求解\(\prod_{i=1}^n\prod_{j=1}^mF_{gcd(i,j)}\),其中\(F\)是斐波那契数列问题分析第一眼化出这个式子肯定是一脸懵,毕竟我们现在做的大......
  • 问题解决:TNS-12543: TNS:destination host unreachable
    环境:11.2.0.3ADG(db11g\db11gadg\db11gcas)在自己先前克隆后的环境互相tnsping报错。tnsping本机ok,tnsping其他机器均报错:[oracle@db11g~]$tnspingjingyuTNSPingUtilityforLinux:Version11.2.0.3.0-Productionon13-MAY-202308:09:11Copyright(c)1997,......
  • cf 870div2 abcd题解
    A题,先假设一个res从0开始,判断说谎人的个数用ans表示,如果res==ans则假设成立#include<iostream>usingnamespacestd;typedeflonglongll;typedefunsignedlonglongull;typedefdoubledb;typedefpair<int,int>PII;constllINF=0x3f3f3f3f;constintN=1e4+10;in......
  • 题解 ABC239F【Construct Highway】
    翻译:给定\(n,m\)和度数数组\(\{d_i\}\),再给你\(m\)条边,请构造一棵\(n\)点的树包含这\(m\)条边,且第\(i\)个点的度数为\(d_i\),或者判断无解。显然,若\(\sumd_i\ne2(n-1)\),则无解。然后对于输入的每条边,使用并查集维护,再求出在这\(m\)条边的基础上每个点还需要多......
  • vi基本入门操作,Ubuntu中vi方向键乱码问题解决方案?
    一、vi基本操作语法:vi+文本名例如创建一个名为text的文本文件进入后先敲击键盘"I"(看个人习惯,敲“a”也是一样的结果,大小写都行),进入插入模式,即可正常输入如果要敲错了内容,和Windows一样,用backspace来删除,也可以用delete键,问题在于用delete键只能删除选中部分的内容,且仅能选......
  • 2023市北区程序设计竞赛题解
    1.分糖果原题: 解题思路:这道题类似于辗转相除法,这道题是辗转相减,每次取余数,如果整除,直接计算答案,并退出,否则继续取余 AC代码:#include<bits/stdc++.h>#definelllonglongusingnamespacestd;intmain(){ lla,b,ans=0;cin>>a>>b; while(a!=b){ if(a<b)swap(a,b......
  • 洛谷 P4544 [USACO10NOV]Buying Feed G - 题解
    https://www.luogu.com.cn/problem/P4544感觉是很没意思的DP+DS优化,以前做过几道更难的题:https://codeforces.com/contest/1788/problem/Ehttps://atcoder.jp/contests/abc288/tasks/abc288_f这种题只要是让我写总是能把代码整的伤痕累累(逃第一眼:我艹不就是一个sbDP吗......
  • 模拟测试题解
    题目链接:https://vjudge.csgrandeur.cn/contest/557480AOJ维护中计算a+b(0<=a,b<=10)。点击查看代码#include<iostream>usingnamespacestd;intmain(){inta,b;cin>>a>>b;cout<<a+b;return0;}B不支持python队列报数,直接模拟即可。点击查看......
  • CF1542E2 题解
    首先,考虑枚举其中一个的逆序对数,这里绕不开的问题就是求\(I_{i,j}\)表示\(1-i\)的排列中逆序对个数为\(j\)的排列数,不妨把这里逆序对变成顺序对(为了方便描述,显然是等价的)。有个很显然的trick:把所有数按\(1-n\)顺序插入。然后当插入第\(i\)个数时,枚举它前面有\(k\)个......
  • 「题解」ABC241Ex Card Deck Score
    小时候最喜欢看的一集没有\(b_i\)怎么做?答案是\([x^m]\prod\frac{1}{1-a_ix}\),我们知道它可以分解为\(\sum\frac{R_i}{1-a_ix}\),其中\(R_i\)是一个常数。具体构造就是上面EI的blog,和中国剩余定理及其类似。那么\(R_i=\frac{1-a_ix}{\prod_j(1-a_jx)}\bmod(1-a_ix)\)......