CF #776 Div.3题解(A ~ E)

这篇博客介绍了如何解决一系列编程问题,包括字符串操作(删除相邻字符),函数优化(最大值计算),点集构成包含序列(权重最小组合),排列还原(序列操作)和考试调度(策略分析)。涉及技巧包括分类讨论、贪心算法、排序构造和递归。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CF #776 Div.3

A Deletions of Two Adjacent Letters(思维)

Description:

给定一个字符串s和字符c 每次可以从字符串s中消除相邻的两个位置的字符 问是否能通过消除来得到字符c

Method:

枚举字符串中每一个c 若前后都为偶数的话 能

Code:

void solve()
{
	string s;
    char c;
    cin >> s >> c;
    for(int i = 0; i < s.size(); i++)
    {
        if(s[i] != c)   continue;
        if(i % 2 == 0 && (s.size() - 1 - i) % 2 == 0)
        {    puts("YES"); f = 1;    break;}
    }
    if(f == 0)  puts("NO");
}

B DIV + MOD(分类讨论 + 贪心)

Description:

定义一个函数f(x) = x / a + x mod a

给定上下界l r 整数a

求在[l, r]内的f(x) Max

Method:

分类讨论 要么让/尽量大 要么让%尽量大

前一种是 r / a + r % a;

后一种是选接近r的a的倍数 - 1

t = r / a * a - 1;(t >= l才成立)

Code:

void solve()
{
	int l, r, a;
	cin >> l >> r >> a;
	int res = r / a + r % a;
	int t = r / a * a - 1;
	if(t >= l)	res = max(res, t / a + t % a);
	cout << res << '\n';
}

C Weight of the System of Nested Segments(排序 + 构造)

Description:

给定m个点和其值 根据要求选择点构成n个数对

要求

  • 必须构成n个数对
  • 必须是层层包含的(内层的数对被外层的数对的坐标区间包含)
  • 保证数对的值之和 取Min

依次输出数对的下标 数对的下标由输入顺序决定

Method:

用结构体存储每一个点的 坐标 值 下标

对值排序 小到大 那么最理想的情况就是找到前2 n个数字 组成数对 但由于要求包含 现实情况并非理想

呸 是个锤子 事实就是那么理想

直接找出2 * n个值最小的数

然后删去多余的点 再对位置排序 每次选最外面的两个

Code:

struct node 
{
	int val, pos, id;
};

int cmp1(node a, node b)
{
	return a.val < b.val;
}

int cmp2(node a, node b)
{
	return a.pos < b.pos;
}

void solve()
{
	int n, m;
    cin >> n >> m;
    vector<node> q(m);

	for(int i = 0; i < m; i++)
	{
		cin >> q[i].pos >> q[i].val;
		q[i].id = i + 1;
	}

	sort(q.begin(), q.end(), cmp1);

	int sum = 0;
	for(int i = 0; i < m; i++)
	{
		if(i < 2 * n)	sum += q[i].val;
		else q.pop_back();
	}

	sort(q.begin(), q.end(), cmp2);

	cout << sum << '\n';
	for(int i = 0; i < n; i++)
		cout << q[i].id << " " << q[2 * n - 1 - i].id << '\n';
}

D Twist the Permutation()

Description:

给定序列 是由1~n的序列经过操作形成的

op:将从1开始长度为k的序列循环右移x次

请问是怎么通过操作还原的 输出数组k

表示操作每段长度循环右移的次数

Method:

既然是通过循环右移得来 那么我们可以通过循环左移将其移动回去

倒序模拟还原 因为当 j 确定了之后 下一次操作只会影响到前 j - 1 位

枚举j 找到 j 目前存在的位置 将其整段循环左移至j 回到原位 先更改备份数组 然后再还原回去

debug 打印数组发现 当j减到0的时候 他应该是要回到i的 手动为他还原一下就好了

Code:

int q[2010], res[2010], backup[2010];

void solve()
{
	int n;
    cin >> n;
    for(int i = 1; i <= n; i++)
        cin >> q[i];
	
	for(int i = n; i >= 1; i--) //枚举数字
	{	
		int idx;
		for(int j = 1; j <= n; j++) //枚举出当前需要的i的坐标j
		    idx = q[j] == i ? j : idx;
		res[i] = idx % i; //若 已经在本位上 左移0次
		for(int j = 1; j <= i; j++)
			if((j - res[i] + i) % i == 0)   backup[i] = q[j]; 
        	//当被移动到0的时候 通过打印数组debug
			else    backup[(j - res[i] + i) % i] = q[j]; //长度为i的数组循环一位res[i]次
		for(int j = 1; j <= i; j++) //备份还原
			q[j] = backup[j];
	}
	for(int i = 1; i <= n; i++)
		cout << res[i] << ' ';
	cout << '\n';
}

E Rescheduling the Exam()

Description:

Method:

Code:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值