CF Div.2 Round 922

CF Div.2 Ronud 922 传送门

A. Brick Wall

题意

给你很多 1 * k(k > 1) 形状的砖块 需要你填满 n * m的砖墙 每一块砖可以不同 (n为高度)

规定 墙的稳定性 = 水平砖块数 - 垂直砖块数

可以横着竖着放都行 需要你计算最大稳定性

思路

1. k为偶 就让 k = 2 答案就是 m / 2 * n

2. k为奇数 贪心 一下我们也不竖着摆 也是横着摆 最后一个 k = 3就行 答案同上

code

#include<iostream>
#include<stack>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstring>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
//#define double long double
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
typedef pair<char, int> PCI;
typedef pair<int, int> PII;
int stif[N];
void solve()
{
	int n, m; cin >> n >> m;
	cout << m / 2 * n << endl;
}
 
signed main()
{
	IOS;
	int tt; cin >> tt;
	while (tt--) solve();
	return 0;
}

B. Minimize Inversions

题意

给你两个长度n的不重复序列 你可以任意选择 i,j 使 ai 和 aj 互换,同时 bi 和 bj 互换 (必须同步)

经过不限次数的移动后 想要知道这两个序列逆序对和最小

n = 2e5

思路

肯定不能O(n^2) 

从example入手:

2 5 6 1 3 4

1 5 3 6 2 4

我希望让它更大的值在右边 这样逆序对肯定可以减少 那么我们尝试按照这个思路移动:

  i   1 2 3 4 5 6

a[i] 2 3 4 5 1 6

b[i] 1 2 4 5 6 3

这样的排序方法是:
1. 对同一个 i 来说 max(ai,bi) 更大的放到右边

2. 对于出现 i = 5,6的情况 就选择min(ai,bi)更小的数往左边放 这样可能是最优的

但是 第二条到底需不需要呢 假如 对 i = 5,6 不遵循第二条再来排序一次:

  i   1 2 3 4 5 6

a[i] 2 3 4 5 6 1

b[i] 1 2 4 5 3 6

我们发现此时仅仅是 a的逆序对+1 b的逆序对-1

并没有差别 所以第二条我们可以舍弃

code

赛时无脑也写上了第二条(现注释掉)

#include<iostream>
#include<stack>
#include<algorithm>
#include<cmath>
#include<vector>
#include<cstring>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
//#define double long double
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
typedef pair<char, int> PCI;
typedef pair<int, int> PII;
int a[N], b[N];
PII st[N * 2];

bool cmp(PII num1, PII num2)
{
	// if (max(num1.first, num1.second) != max(num2.first, num2.second))
	// {
	return max(num1.first, num1.second) < max(num2.first, num2.second);
	// }
	// return min(num1.first, num1.second) < min(num2.first, num2.second);
}

void solve()
{
	int n; cin >> n;
	for (int i = 1; i <= n; i++) cin >> st[i].first;
	for (int i = 1; i <= n; i++) cin >> st[i].second;
	sort(st + 1, st + 1 + n,cmp);
	for (int i = 1; i <= n; i++) cout << st[i].first << ' ';
	cout << endl;
	for (int i = 1; i <= n; i++) cout << st[i].second << ' ';
	cout << endl;
}

signed main()
{
	IOS;
	int tt; cin >> tt;
	while (tt--) solve();
	return 0;
}

C. XOR-distance

题意

给你一个 a,b,r 希望从[0,r]中找到一个 x 使得 |(a⊕x)-(b⊕x)| 最小 

思路

简而言之就是让 (a⊕x) 和 (b⊕x) 更接近

下面默认 a > b

考虑一个简单情况 (下面都化为二进制

    i  3 2 1 0

a = 1 0 0 1

b = 0 1 1 0

很显然a更大 在有限的 r 下 我们希望的肯定是 ai = 1 且bi = 0 时 反转

也就是大的变小 小的变大 差距就会减少

这个地方可能会有的疑问是 这一位我们不转 之后能转的不是都能转了吗

但是从贡献上说第i位的贡献-1 才等于后面所有位能贡献值之和:

2^i - 1 = \sum_0^{i-1} 2^j

也就是为了让差距变的更小 i 位能转就转!不要考虑后面都能弥补什么的

接下来是一个很难想的情况 在最高位 满足 ai = 1 且bi = 0 的时候需要反转吗

假如反转了 a -= (1ll << i)     b += (1ll << i) 

会导致 b 成为最大的数 这是不是又回到了原来的情况 (深思熟虑一下

比如

1 1 0 1

0 1 1 1

最高位不转的时候 现在就是最佳答案 

转的话:

0 1 1 1

1 1 0 1

是不是一样等于没转 反而需要的r更大了……理解一下吧)

code

#include<iostream>
#include<cstdio>
#include<stack>
#include<vector>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#include<set>
#include<vector>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define int long long
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
//typedef pair<char, int> PCI;
//const int N = 110;
const int INF = 0x3f3f3f3f;
//const int N = 1010;
//int dx[4] = { 1,0,-1,0 }, dy[4] = {0,1,0,-1};
const int N = 2e5 + 10;
int n, m, cnt;
int a[N];
int sum[N];
int res[N];
void solve()
{
	int a, b, r; cin >> a >> b >> r;
	string r1, r2; 
	if (a == b)
	{
		cout << 0 << endl;
		return;
	}
	if (a < b) swap(a, b);
	for (int i = 0; i < 64; i++)
		r1 += (((a >> i) & 1) ^ 48);
	for (int i = 0; i < 64; i++)
		r2 += (((b >> i) & 1) ^ 48);
	int vis[65] = { 0 };
	int high = 0;
	for (int i = 63; i >= 0; i--)
	{
		if (((a >> i) & 1) != ((b >> i) & 1))
		{
			high = i;
			break;
		}
	}
	for (int i = 0; i < high; i++)
		if (((a >> i) & 1) && !((b >> i) & 1)) vis[i] = 1;
	int limit = 1;
	for (int i = 63;i >= 0; i--)
	{
		if (((r >> i) & 1) && !vis[i]) limit = 0;
		if (vis[i])
		{
			if (limit)
			{
				if ((r >> i) & 1) swap(r1[i], r2[i]);
				else continue;
			}
			else swap(r1[i], r2[i]);
		}
	}
	int ans1 = 0, ans2 = 0;
	for (int i = 0; i < 64; i++)
	{
		if (r1[i] == '1') ans1 += (1ll << i);
		if (r2[i] == '1') ans2 += (1ll << i);
	}
	cout << ans1 - ans2 << endl;
}
 
signed main()
{
	IOS;
	int tt = 1; cin >> tt;
	while (tt--) solve();
	return 0;
}

D.Blocking Elements

待补..

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值