Codeforces Round 922 (Div. 2)(A~D)

文章详细解释了四个编程题目:BrickWall涉及填满格子的最优策略,MinimizeInversions要求在保持数组有序的同时减少逆序对,XOR-distance通过异或操作调整数列,BlockingElements使用二分查找和双端队列解决区间和限制问题。
摘要由CSDN通过智能技术生成

A. Brick Wall

用横着的砖填满格子

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
void solve()
{
    int n, m;
    cin >> n >> m;
    cout << m / 2 * n << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}

B. Minimize Inversions

这题要求 A A A数组和 B B B数组中的逆序对个数之和最少

我们假设 A A A数组有序,此时调整 A A A数组中的元素,若交换 a i a_i ai a j a_j aj,则会多出 j − i j - i ji个逆序对,是最不优情况

所以当一个数组有序的时候即为答案

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
struct sj
{
    int a, b;
} x[N];
bool cmp(sj x, sj y)
{
    return x.a < y.a;
}
void solve()
{
    int n;
    cin >> n;
    for(int i = 1;i <= n;i++)
    cin >> x[i].a;
    for(int i = 1;i <= n;i++)
    cin >> x[i].b;
    sort(x+1,x+n+1,cmp);
    for(int i = 1;i <= n;i++)
    cout << x[i].a << " ";
    cout << '\n';
    for(int i = 1;i <= n;i++)
    cout << x[i].b << " ";
    cout << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}

C. XOR-distance

我们使小的数变大,大的数变小,但是小的数不能大于大的数

记小的数为 a a a,大的数为 b b b,如果当前位 a a a 0 0 0 b b b 1 1 1,通过异或操作,可以使得前位 a a a 1 1 1 b b b 0 0 0,从最高位到最低位依次操作

注意,每次操作要考虑是否超过范围 r r r

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
void solve()
{
    int a, b, r;
    cin >> a >> b >> r;
    int rr = r, cnt = 0, sum = 0;
    while(rr > 0)
    {
        rr /= 2;
        cnt++;
    }
    for(int i = cnt;i >= 0;i--)
    {
        if(a > b)
        swap(a, b);
        int aa = (a ^ (1LL << i)), bb = (b ^ (1LL << i));
        if(((1LL << i) & a) == 0 && ((1LL << i) & b) > 0 && aa < bb)
        {
            if(sum + (1LL << i) <= r)
            {
                sum += (1LL << i);
                a = (a ^ (1LL << i));
                b = (b ^ (1LL << i));
            }
        }
    }
    cout << abs(a - b) << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}

D. Blocking Elements

二分答案,看选中的数之和是否超过 m i d mid mid

d p i dp_i dpi为最后一个选中的数为 a i a_i ai时的最小代价,所以我们只需要判断 d p n + 1 dp_{n+1} dpn+1 m i d mid mid的大小关系

如果当前选中的位置为 i i i,由于要满足每段之和小于等于 m i d mid mid,所以我们可以得到满足条件的最前面的选点 j j j,可以通过双指针处理出 j j j

所以 d p i dp_i dpi的转移方程为 d p i = m a x ( m i n ( d p [ k ] ) + a [ i ] ) , ( j ⩽ k ⩽ i − 1 ) dp_i = max(min(dp[k]) +a[i]),(j \leqslant k \leqslant i - 1) dpi=max(min(dp[k])+a[i]),(jki1)

为了使时间复杂度满足题目要求,我们可以用双端队列优化,总时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e16;
const ll mod = 1e9 + 7;
const int base = 13331;
void solve()
{
    int n;
    cin >> n;
    vector<int> a(n+5);
    for(int i = 1;i <= n;i++)
    cin >> a[i];
    int l = 1, r = 1e16;
    while(l <= r)
    {
        deque<int> q;
        q.push_back(0);
        int mid = (l + r) / 2, cnt = 0;
        vector<int> dp(n+5);
        for(int i = 1, j = 0;i <= n + 1;i++)
        {
            while(cnt > mid)
            cnt -= a[++j];
            while(!q.empty() && q.front() < j) q.pop_front();
            dp[i] = dp[q.front()] + a[i];
            while(!q.empty() && dp[q.back()] >= dp[i]) q.pop_back();
            cnt += a[i];
            q.push_back(i);
        }
        if(dp[n + 1] > mid)
        l = mid + 1;
        else
        r = mid - 1;
    }
    cout << l << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}
  • 31
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值