每日训练-7.7

这篇博客探讨了几道涉及差分数组和区间操作的算法题目,包括道路铺设、加加减减、积木大赛和FibonacciAdditions等。通过实例解析,展示了如何利用差分数组构造原数组并解决区间操作问题,涉及知识点包括差分、区间减操作和正负数中和策略。同时,文章还提供了解决FixedPointGuessing问题的二分构造交互思路。

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

1.道路铺设

1.题意

道路铺设
在这里插入图片描述

2.知识点

差分

3.思路

维护区间的减可以构造原数组的差分数组,题意要求最后原数组都为0,等价于差分数组都为0。
注意到”需要保证,区间内的每块区域在填充前下陷深度均不为 0 “,这句话则保证了从下标为1开始的
每一段差分数组的正数和大于负数和(相反数),而区间减在差分数组中表现为 a[L] --,a[R + 1] ++,
所以我们只需要存储所有正数的和即为答案(因为正数和大于负数,所以负数可以使用正数的差分操作来中和掉)

4.代码
#include<bits/stdc++.h>
using namespace std;

const int N = 100010;

int n;
int a[N], tmp[N];

signed main() {
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> tmp[i];
    for (int i = 1; i <= n; i ++ ) a[i] = tmp[i] - tmp[i - 1];
    
    int res = 0;
    for (int i = 1; i <= n; i ++ ) if (a[i] > 0) res += a[i];
    cout << res << endl;
    return 0;
}

2.加加减减

1.题意

加加减减
在这里插入图片描述

2.知识点

差分

3.思路

首先构造差分数组,要使原数组所有值相等只需要将差分数组除第一个元素外变为0就能实现。
两种操作分别是
1.a[L] – , a[R + 1] ++
2.a[L] ++, a[R + 1] –
这意味着我们可以通过若干操作使一段区间中的正负数相中和,最终区间内会剩下溢出的一个正数或负数,通过这个数可以对数组头元素加或减 (0 ~ abs(余下的值)),从而产生不同的方案,即方案数等于abs(余值) + 1。

4.代码
#include<bits/stdc++.h>
using namespace std;

const int N = 1000010;

int n;
int a[N], tmp[N];

signed main() {
	cin >> n;
	for (int i = 1; i <= n; i ++ ) cin >> tmp[i];
	for (int i = 1; i <= n; i ++ ) a[i] = tmp[i] - tmp[i - 1];

	int sum[2] = {0, 0};
	for (int i = 2; i <= n; i ++ ) {
		if (a[i] > 0) sum[0] += a[i];
		else sum[1] -= a[i];
	}

	cout << max(sum[0], sum[1]) << endl;
	cout << abs(sum[0] - sum[1]) + 1 << endl;
	return 0;
}
5.小结

原数组所有值相等 <=> 差分数组除第一个元素外 == 0

3.积木大赛

1.题意

积木大赛
在这里插入图片描述

2.知识点

chafen

3.思路

与第一题类似

4.代码
#include<bits/stdc++.h>
using namespace std;

const int N = 100010;

int n;
int tmp[N], a[N];

signed main() {
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> tmp[i];
    for (int i = 1; i <= n; i ++ ) a[i] = tmp[i] - tmp[i - 1];
    
    int res = 0;
    for (int i = 1; i <= n; i ++ ) if (a[i] > 0) res += a[i];
    cout << res << endl;
    return 0;
}

4.Fibonacci Additions

1.题意

Fibonacci Additions
在这里插入图片描述

2.知识点

差分 构造 思维

3.思路

参考
在这里插入图片描述
在这里插入图片描述

4.代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 300010;

int n, m, MOD;
int A[N], B[N], C[N], D[N];
int fib[N];
char op; 
int L, R;
int zero = 0;

void upd(int id, int x) {
    if (1 <= id && id <= n) {
        zero -= (D[id] == 0);
        D[id] += x % MOD;
        D[id] = (D[id] + MOD) % MOD;
        zero += (D[id] == 0);
    }
}

void solve() {
    cin >> n >> m >> MOD;
    for (int i = 1; i <= n; i ++ ) cin >> A[i];
    for (int i = 1; i <= n; i ++ ) cin >> B[i];
    for (int i = 1; i <= n; i ++ ) C[i] = A[i] - B[i];

    D[1] = C[1] % MOD;
    D[2] = (C[2] - C[1] + MOD) % MOD;

    for (int i = 3; i <= n; i++)D[i] = (C[i] - C[i - 1] - C[i - 2] + 2 * MOD) % MOD;

    fib[1] = 1, fib[2] = 1;

    for (int i = 3; i < N; i++)fib[i] = (fib[i - 1] + fib[i - 2]) % MOD;
    for (int i = 1; i <= n; i++)zero += (D[i] == 0);

    while (m -- ) {
        cin >> op >> L >> R;
        if (op == 'A') {
            upd(L, 1);
            upd(R + 1, -fib[R - L + 2]);
            upd(R + 2, -fib[R - L + 1]);
        }else {
            upd(L, -1);
            upd(R + 1, fib[R - L + 2]);
            upd(R + 2, fib[R - L + 1]);
        }
        if (zero == n) cout << "YES" << endl;
        else cout << "NO" << endl; 
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    solve();
    return 0;
}

5.Fixed Point Guessing

1.题意

Fixed Point Guessing
在这里插入图片描述

2.知识点

二分 构造 交互

3.思路

通过二分,将数组分为两块,则对于下标区间 [L,R] ,统计:值在 [L,R] 的元素个数:

若下标 [L,R] 内部两数进行交换,则值增加 2。
若下标 [L,R] 的数与其他区间的数进行交换,则值不变。
若下标 [L,R] 的数没有发生交换,则答案增加 1 。

4.代码
#include <bits/stdc++.h>
using namespace std;
 
const int N=200010;

int n;
bool check(int l,int r) {
    printf("? %d %d\n",l,r);
    fflush(stdout);

    int cnt = 0;
    for (int i = 0; i < r - l + 1; i ++ ) {
        int x;
        cin >> x;
        cnt += x >= l && x <= r;
    }
    return cnt % 2 == 1;
}
void solve() {
    cin >> n;
    int l = 0, r = n;
    while (l+1<r) {
        int md=(l+r)>>1;
        if (check(1,md)) r=md; else l=md;
    }
    printf("! %d\n",r);
    fflush(stdout);
}

signed main() {
    int T; 
    cin >> T;
    while (T -- ) solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pale_B

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值