CF 977 Review

CF 977 Review

掉大分了,我去,绿名也是可以掉分的,我去你简直太牛了sgh。

我是真正的飞舞。

A

排序以后贪心或者直接优先队列模拟即可,都可以过。

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
} 
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
int n,m,k;
int main()
{
	int T;
	re(T);
	priority_queue<int,vector<int>,greater<int>> q;
	while(T--)
	{
		re(n);
		int tmp;
		for(register int i=1;i<=n;++i)re(tmp),q.push(tmp);
		for(register int i=1;i<=n-1;++i)
		{
			int x=q.top();q.pop();
			int y=q.top();q.pop();
			q.push((x+y)/2);
		}
		wr(q.top()),putchar('\n');
		q.pop();
	}
	return 0;
}

B

分析

给定一个序列 \({a_n}\)\(x>0\) ,可以任意次数的将序列中的任意一个数加上 \(x\) ,求在最优操作下序列 mex 的最大值。

需要明确的是我们一定是要尽可能地让较小的数都能够存在。

因为只能执行加的操作 ,所以达成这一目的一定是要把 多余的 并且 更小的 数进行操作得到的。

那么我们只需要把序列sort一遍然后模拟即可,注意一遍模拟一遍检查是否出现答案,还要记录当前数字的个数。

复杂度 \(O(n\log n)\) 可以通过。

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
} 
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
int n,x;
int a[200010]; 
int main()
{
	int T;
	re(T);
	while(T--)
	{
		set<int> s;unordered_map<int,int> CNT;
		re(n),re(x);
		for(register int i=1;i<=n;++i)re(a[i]);
		sort(a+1,a+n+1);
		int cnt=1;
		a[n+1]=-1;
		for(register int i=1;i<=n;++i)
		{
			if(a[i]==a[i+1])
				cnt++;
			else 
			{
				s.insert(a[i]);
				CNT[a[i]]=cnt;
				cnt=1;
			}
		}
		int las=-1;
		for(auto it:s)
		{
			if(it-las>=2){wr(las+1),putchar('\n');goto A;}
			if(CNT[it]>1)
			{
				if(!s.count(it+x))s.insert(it+x); 
				CNT[it+x]+=CNT[it]-1;
			}
			las=it;
		}
		wr(las+1),putchar('\n');
		A:continue;
	}
	return 0;
}
/*
1
6 1
1 3 4 1 0 2
*/

C(easy)

题意不多赘述,因为太难赘述了。

分析

先看一组样例 :

a:1 2 3 4

b:1 2 3 4   2 3 4 1   2 3 1 4

你会发现只要前四个能够匹配上,好像后面一定能够满足。

那如果我后面八个再写杂乱无章一点,比如 2 1 3 2 1 4 1 2 ,会发现无论怎么写都一定能够满足。

那如果我再写的极限一点:

a:1 2 3 4

b:1 2 3     2 3 4 1  2 3 1 4

这下好像仍然可以,但前四个就不一定一样了。

看看样例里面不合法的一个情况呢?

a:3 1 4 2 5
b:3 1 4 5 2 3 4

这下前三个相同,但是又不合法了,说明和前几位相同实际上没有什么必要的关系。

多举几组反例会发现,b 里面的数字必须按照 a 中的顺序出现,言下之意,当 \(a_i\) 没有第一次出现的时候,\(a_{i+1}\) 就不能先出现,因为此时就不可以通过操作使 \(a_{i+1}\) 出现在 \(a_i\) 前面。

根据以上分析,我们只需要记录每个 \(a_i\) 第一次出现的位置即可。或者说直接按位匹配,不合法就直接输出。

(写的时候差临门一脚了,还是自己太笨了,脑子转的不够快)

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
} 
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
int n,m,q;
const int N=2e5+10;
int a[N],b[N],c[N];
inline void solve()
{
	re(n),re(m),re(q);
	for(register int i=1;i<=n;++i)re(a[i]);
	for(register int i=1;i<=m;++i)re(b[i]);
	int cnt=0;b[m+1]=0;
	for(register int i=1;i<=m;++i)
	{
		if(b[i]==b[i+1])continue;
		c[++cnt]=b[i];
	}
	vector<int> vis(n+10,0);
	for(register int i=1,p=1;i<=cnt;++i)
	{
		if(c[i]==a[p])vis[a[p++]]=1;
		else if(!vis[c[i]])
		{
			puts("TIDAK");
			return ;
		}
	}
	puts("YA");
}
int main()
{
	int T;
	re(T);
	while(T--)
		solve();
	return 0;
}

(去重并不是必要的)

C(hard)

挖个坑

D

这个太难了暂时不补了

E

挖个坑

posted @ 2024-10-06 17:38  Hanggoash  阅读(17)  评论(0编辑  收藏  举报
动态线条
动态线条end