首页 > 其他分享 >洛谷 CF1257F Make Them Similar 灰 题解

洛谷 CF1257F Make Them Similar 灰 题解

时间:2022-09-27 17:03:11浏览次数:55  
标签:Them 洛谷 val int 题解 res 15 include 式子

前言

本题解采用折半搜索算法完成,对于不打算用这种方法的同学,这篇题解可能会浪费你人生中宝贵的十几分钟。

思路

此题似乎找不出什么好的性质,那么考虑暴力。

发现 \(x,a\) 都在 \(2^{30}\) 内,直接枚举必然无法承受,怎么办?折半!

我们把 \(x,a_i\) 劈成两半,一半为前 \(15\) 位,一半为后 \(15\) 位,分别暴力计算。

令 \(c_i\) 表示 \(a_i \oplus x\) 得到的数的前 \(15\) 位的 \(1\) 的个数(前 \(15\) 位,指:从高往低数前 \(15\) 位);

令 \(d_i\) 表示 \(a_i \oplus x\) 得到的数的后 \(15\) 位的 \(1\) 的个数(后 \(15\) 位,指:从低往高数前 \(15\) 位)。

那么 \(c_i + d_i\) 就表示 \(a_i \oplus x\) 得到的数在二进制表示下 \(1\) 的个数,题目要求所有的 \(c_i + d_i\) 必须相等,那么我们可以列出必须满足的式子:\(c_i + d_i = c_{i-1} + d_{i-1},\ 2 \le i \le n\)。

你会发现这个式子没有简单的判定方法,那考虑把式子换一种形式,既然要保证所有的 \(c_i + d_i\) 相等,那么只要满足 \(c_i + d_i = c_1 + d_1\) 就可以了。

貌似有一些思路,但是还没有复杂度较低的判定方法,那就再把式子换一种形式:\(c_i - c_1 = d_1 - d_i\),这样就可做了。

实现

我们求 \(c\) 数组的时候把每一个 \(x\) 所对应的所有 \(c_i - c_1\) 存下来。求 \(d\) 数组的时候,把所有 \(d_1 - d_i\) 存下来。

如果某一个 \(x\),与其对应的 \(c_i - c_1\) 和 \(d_1 - d_1\) 每一项都相等,那么就满足条件了,输出即可。

插曲

如何快速地求一个数在二进制下的 \(1\) 的个数?先上代码~

int get_cnt(int val)
{
	int res = 0;
	while (val) val &= val - 1, res ++ ;
	return res;
}

我们举个例子来看一看

总的来说 \(x-1\) 相当于是把 \(x\) 在二进制表示下最靠后的 \(1\) 以及这个 \(1\) 后面的所有 \(0\) 按位取反,得到的数再与上 \(x\) 相当于把最靠后的 \(1\) 消去了。

Code

#include <iostream>
#include <cstring>
#include <map>
#include <vector>

using namespace std;

const int N = 110;
const int Mo = (1 << 15) - 1;

int n;
int a[N];
map<vector<int>, int> mp;

int get_cnt(int val)
{
	int res = 0;
	while (val) val &= val - 1, res ++ ;
	return res;
}

int main()
{
	cin >> n;
	for (int i = 1; i <= n; i ++ ) cin >> a[i];
	for (int x = 0; x < (1 << 15); x ++ )
	{
		int c1 = get_cnt((a[1] >> 15) ^ x);
		vector<int> vec;
		for (int i = 2; i <= n; i ++ ) vec.push_back(get_cnt((a[i] >> 15) ^ x) - c1);
		mp[vec] = x;
	}
	for (int x = 0; x < (1 << 15); x ++ )
	{
		int d1 = get_cnt((a[1] & Mo) ^ x);
		vector<int> nw;
		for (int i = 2; i <= n; i ++ ) nw.push_back(d1 - get_cnt((a[i] & Mo) ^ x));
		if (mp.count(nw))
		{
			cout << (mp[nw] << 15) + x << endl;
			return 0;
		}
	}
	cout << -1 << endl;
	return 0;
}

完结撒花

这是我折半搜索第一次学明白的题了,也是我第一道灰题!收~

标签:Them,洛谷,val,int,题解,res,15,include,式子
From: https://www.cnblogs.com/LittleMoMol-kawayi/p/LuoGu_solution_CF1257F.html

相关文章

  • LG4463 calc 题解
    传送门题意一个序列$a_1,a_2,\dots,a_n$是合法的,当且仅当:$a_1,a_2,\dots,a_n$都是\([1,k]\)中的整数。$a_1,a_2,\dots,a_n$互不相等。一个序列的值定义为它里......
  • P4965 题解
    题目传送门被同机房神犇使用一顿晚饭的时间爆切并当成作业布置给我的题...虽然是紫,但实际难度处于可以接受的范围内。题目分析开始的思路是\(\text{set}\)乱搞,因为发......
  • AtCoder ABC 270 题解(D-F)
    AtCoderABC270题解(D-F)D-Stones(博弈DP)题目:​ 现在有一堆石子,一个序列a表示每次可以从石头里拿走多少个石子。当无法再拿出石头的时候,游戏结束。两边都以最佳策略......
  • 题解【CF1436E Complicated Computations】
    CF1436EComplicatedComputations解题报告。不一定更好的阅读体验。对于一个数\(x\),考虑什么条件\(x\)可以作为答案。首先要满足\(\forally\in[1,x)\),\(y\)......
  • SpringBoot+Mybatis-Plus 数据表字段是关键字的问题解决
    如果字段名是关键字,用mybatisplus时会报以下错误:badSQLgrammar[];nestedexceptionisjava.sql.BatchUpdateException:ORA-01747:user.table.column,table.column......
  • 力扣算法第1题--两数之和(暴力题解&优化题解)
    两数之和题目描述:给定一个整数数组nums 和一个整数目标值target,请你在该数组中找出和为目标值target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输......
  • P2044 随机数生成器 题解
    这么标准的不动点居然只有一篇不动点题解?而且唯一的不动点题解关于不动点的描述还是错的?所以,来写一篇题解讲讲,MO中是怎么弄这种一阶线性递推式的。单个数,虽然省常数,却......
  • P6835 [Cnoi2020]线形生物 题解
    通过这道题可以看出来pz根本不会期望考虑期望线性性质,设\(E_{x\toy}\)表示从\(x\)走到\(y\)的期望步数,那么有\(E_{1\ton+1}=\sum_{i=1}^nE_{i\toi+1}\),因此考......
  • P2569 [SCOI2010]股票交易 题解
    设\(f_{i,j}\)表示第1天至第\(i\)天,手上有\(j\)股股票时拥有的最多钱。考虑转移,首先就有\(f_{i,j}=-j\timesap_i\)即单纯买入,然后由转移方程定义有\(f_{i,j}=......
  • CF1155D 题解
    题目传送门题目分析说实话,第一眼这题以为是贪心...(事实上我看所有动态规划都像贪心)。然后接着发现贪心明显做不了,又看见最大子段和,很容易联想到\(\text{dp}\)。在设计......