Codeforces Round 992 (Div. 2) 题解(A~D)


广告:starrycoding 9 折优惠码: FV7B04LL

E 有空再补
构造场, 构造低手掉分.

A

不记得为什么卡了, 居然写了 7min.

思路

n102, 甚至可以使用 n3 算法.
枚举每个 ai, 判断 ai{a1,a2,,ai1}{ai+1,ai+2,,an} 组合后, 是否可以都不被 k 整除.

复杂度 O(n2).

代码

void func(void)
{
	int n,k;
	cin >> n >> k;
	vector<int> a(n+1);
	for(int i=1;i<=n;++i)	cin >> a[i];
	for(int i=1;i<=n;++i)
	{
		int cnt = 0;
		for(int j=1;j<=n;++j)
		{
			if(i == j)	continue;
			int X = abs(a[i]-a[j]);
			if(X % k != 0)	cnt ++;
		}
		if(cnt == n-1)
		{
			cout << "YES\n" << i << '\n';
			return ;
		}
	}
	cout << "NO\n";
}

B

思路

对于操作 2, 每次操作, 若是区间内有 超过一半(向上取整), 的位置有 1, 那么区间内所有数都为 1.

起始必须放置一个 1.
那么我们从 1 开始放置(俺寻思, 事实上放在中间, 左右轮流放不会影响结果, 不做证明了),

1 放置后, 2 最多放置在 4((1+1)2) 的位置, 才能满足 lr 半数有 1,
3 最多放置在 10((4+1)2).

设当前 i 的总数为 cnt.
可以得到, 第 i1, 可以放置在(cnt+1)2 的位置.

那么根据上述模拟即可.

复杂度 O(logn)

代码

void func(void)
{
	int n;
	cin >> n;
	int X = 1,cnt = 0;
	while(X < n)
	{
		X = (X+1)*2;
		cnt ++;
	}
	cout << cnt+1 << '\n';
}

C

赛时没战意, 这题都没出.
这题不是很好讲, 需要结合图推.

思路

不递减排列是满足条件的.
1,2,3,,n1,n, 满足条件.

S(p)= 1+2++n3+n2+n1+1+2++n3+n2+1+2++n3  +1+2+1

要满足上述内容, 除了 n 之外的所有数, 两侧至少有一个 大于自己的数.

那么如果我们从 n开始放置:
n1 可以放置在 n 在左右侧.
n2 可以放在 整体 的左右, 但是不能方阵 n,n1 之间, 因为会让 n1 捕鱼 n 相邻, 就没有再比它大的数了.

那么从 n 放置到 1, 每次只能放置在整体的左右.

但是若是从 n 开始放置, 不好判断字典序顺序(看下述可得).

反向考虑, 从 1 开始.
下述内容画一画就很明显了
1 只能防止在最左侧/最右侧.
2 只能防止在 1 只内的最左/最右(1 在左时, 2 放在 1 由或 最右, 反之亦然. )
3 只能放在新区间的最左/最右.

那么总共有 2n1 种放法.

如果 1 在最前, 字典序就是前 2n1/2(也就是2n2).
否则, 字典序就是 2n1/2+12n1.

对于 2, 如果 2 在新区间最前, 其字典序在此范围的 12n3
即如果 1 在最前, 2 在最前的字典序范围 12n3.
如果 1 在最后, 2 在最后的字典序范围 2n2+12n1.

又因为 2nsizeof(longlong), 所以只能选择别的方法表示.

根据上述分析, 一次可以排除掉整体区间的 一半, 那么多次就是典型的 log.
那么可以把 2nk 表示为 nlogk

具体看代码吧.

复杂度

代码

int qpow(int a,int b)// 快速幂
{
	int res=1;
	while(b)
	{
		if(b&1)res=res*a;
		a=a*a;
		b=b>>1;
	}
	return res;
}

void func(void)
{
	int n,k;
	cin >> n >> k;
	vector<int> a(n+1);
	int l = 1,r = n;
	if(log2(k) > n-1)// c++ 内置log_2函数
	{
		cout << -1 << '\n';
		return ;
	}
	for(int i=1;i<=n-1;++i)
	{
		if(!k || log2(k) <= n-i-1)
		{
			a[l ++] = i;
		}
		else
		{
			a[r --] = i;
			k -= qpow(2,n-i-1);// 能够减去的数小于 10^12
		}
	}
	a[r --] = n;
	for(int i=1;i<=n;++i)	cout << a[i] << ' ';
	cout << '\n';
}

D

沟槽的领接表, 太久没写, 整体clear tle了, 多浪费 1h, 但是多了一种思路.
一题三解, 真有我的.
前置知识: dfs, 领接表.
思路二需要: 埃氏筛.
思路三需要 set, set.lower_bound().

三解太耗精力, 之后可能会补充吧.

解法 1

思路

比较俺寻思, 但是感觉更好理解.

  • 要求相邻两数差不为质数, 偶数 除了2, 都不为质数.
  • 总共只能使用 2n 个点.

先假设一条 5 条的链, 我们只放奇数, 那么:
alt text
是可以满足情况的.

但是若是点很少:
alt text
是放不下的.

再考虑花形:
alt text
三个点的链也属于花形.

整个图可以可以视作若干个上述小单元的组合(链和花).

每个小单元则只能使用 cnt2个数.

2不能使用, 每个单元必然有一个数不能放置.

如果填入 1, 那么该单元就可以放满了:
alt text

那么从根节点出发, 每次优先放 1, 其次放差 2 以外同奇偶性的数.

本质还是解法1, 只是实现不同.

代码

void dfs(int p,int lp)
{
	if(a[p].size() <= 1)	return ;
	int cnt = a[p].size() - 1;
	stack<int> X;
	if(ans[p]&1)
	{
		if(st2.lower_bound(ans[p]+1) != st2.end() && *st2.lower_bound(ans[p]+1) == ans[p]+1)
		{
			X.push(ans[p]+1);
			st2.erase(ans[p]+1);
		}
		vector<int> stp;
		while(X.size() != cnt)
		{
			int temp = *st1.begin();	st1.erase(temp);
			if(temp != ans[p] + 2 && temp != ans[p]-2)	X.push(temp); 
			else	stp.push_back(temp);
		}
		for(auto &i : stp)	st1.insert(i);
	}
	else
	{
		if(st1.lower_bound(ans[p]+1) != st1.end() && *st1.lower_bound(ans[p]+1) == ans[p]+1)
		{
			X.push(ans[p]+1);
			st1.erase(ans[p]+1);
		}
		vector<int> stp;
		while(X.size() != cnt)
		{
			int temp = *st2.begin();	st2.erase(temp);
			if(temp != ans[p] + 2 && temp != ans[p]-2)	X.push(temp);
			else	stp.push_back(temp);
		}
		for(auto &i : stp)	st2.insert(i);
	}
	for(auto &i : a[p])
	{
		if(i == lp)	continue;
		ans[i] = X.top(); 
		X.pop();
		
	}
	for(auto &i : a[p])
	{
		if(i == lp)	continue;
		dfs(i,p);
	}
}

void func(void)
{
	int n;
	cin >> n;
	for(int i=2;i<=n<<1;++i)
	{
		(i&1) == 1 ? st1.insert(i) : st2.insert(i);
	}
	for(int i=1;i<=n;++i)	a[i].clear();
	int x,y;
	for(int i=1;i<n;++i)
	{
		cin >> x >> y;
		a[x].push_back(y);
		a[y].push_back(x);
	}
	a[1].push_back(0);
	ans[1] = 1;
	dfs(1,0);
	for(int i=1;i<=n;++i)	cout << ans[i] << ' ';
	cout << '\n';
}

解法 2

从此视频学习: Codeforces Round 992 (Div. 2) 题目讲解 ABCDE (CF2040)

两个解法一直在 tle, 只能找了题解.

思路

和解法 1 类似, 每个小单元最多使用 2k 个数. 而用 12, 同奇偶性的数刚好在范围内.

代码

int X;
vector<int> a[N],ans(N);

void dfs(int p,int lp)
{	
	ans[p] = X --;
	int cnt = 0;
	for(auto &i : a[p])
	{
		if(i == lp)	continue;
		if(ans[p]-X == 2) X -= 2;
		else if(ans[p]-X != 1 && (ans[p]-X)&1)	X --;
		cnt ++;
		dfs(i,p);
	}
	int len = a[p].size();
}

void func(void)
{
	int n;
	cin >> n;
	for(int i=1;i<=n;++i)	a[i].clear();
	int x,y;
	for(int i=1;i<n;++i)
	{
		cin >> x >> y;
		a[x].push_back(y);
		a[y].push_back(x);
	}
	X = n<<1;
	dfs(1,0);
	for(int i=1;i<=n;++i)	cout << ans[i] << ' ';
	cout << '\n';
}

解法 3

起始思路, 根本没想到是领接表问题.

思路

既然每条边差都为非素数, 那么dfs到每个点, 给子节点赋值 + 非素数即可. 复杂度懒得证明了.

代码

#include<bits/stdc++.h>
#define Start cin.tie(0), cout.tie(0), ios::sync_with_stdio(false)
#define PII pair<int,int> 
#define x first
#define y second
#define ull unsigned long long
#define ll long long
using namespace std;

const int M = 1000000007;
const int N = 2e5 + 10;

int len;
bitset<N<<1> vis;
vector<int> v(1,1),pri,a[N],ans(N);

void func(void);

void dfs(int p,int lp)
{
	int X = 0;
	for(auto &i : a[p])
	{
		if(i == lp)	continue;
		while(vis[ans[p]+v[X]])	X ++;
		ans[i] = ans[p] + v[X];
		vis[ans[i]] = true;
		dfs(i,p);
	}
}

signed main(void)
{
	Start;
	int n = N<<1;
	for(int i=2;i<=n;++i)
	{
		if(!vis[i])	pri.push_back(i);
		for(int j=0;pri[j]<=n/i;++j)
		{
			v.push_back(pri[j] * i);
			vis[pri[j] * i] = true;
			if(i % pri[j] == 0)	break;
		}
	}
	len = v.size();
	sort(v.begin(),v.end());
	int _ = 1;
	cin >> _;
	while(_--)	func();
	return 0;
}

void func(void)
{
	int n;
	cin >> n;
	vis.reset();
	for(int i=1;i<=n;++i)	a[i].clear();
	int x,y;
	for(int i=1;i<n;++i)
	{
		cin >> x >> y;
		a[x].push_back(y);
		a[y].push_back(x);
	}
	ans[1] = 1;
	dfs(1,0);
	for(int i=1;i<=n;++i)	cout << ans[i] << ' ';
	cout << '\n';
}
posted @   zerocloud01  阅读(124)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示