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
思路
肯定不能
从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 才等于后面所有位能贡献值之和:
也就是为了让差距变的更小 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
待补..