当前位置: 首页 > article >正文

Codeforces Round 971 (Div. 4) (A~G1)

A、B题太简单,不做解释

C

对于 x y 两个方向,每一个方向至少需要 x / k 向上取整的步数,取最大值。
由于 x 方向先移动,假如 x 方向需要的步数多于 y 方向的步数,那么最后 y 方向的那一步就不需要了,答案减 1

代码

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cmath>
using namespace std;
using LL = long long;

void slove()
{
    int x, y, k; cin >> x >> y >> k;
    int h = ceil((double)y / k);
    int l = ceil((double)x / k);
    int res = max(h, l);
    res *= 2;
    if (l > h) res--;
    cout << res << endl;
} 

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1; cin >> t;
    while (t--) slove();
    return 0;
}

D

注意到 y 的范围为: [0, 1],当两点连线垂直 x 轴时,与其余任意点都可以组成直角形。
还有一种组成直角三角形的情况是:一条水平线的点和另一条水平线的两个点组成直角三角形,单独的点的 x 轴坐标位于两点中间,且距离两点长度为 1(由等腰直角三角形的性质可得)

代码

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <cmath>
#include <map>
using namespace std;
using LL = long long;

void slove()
{
    int n; cin >> n;
    vector<vector<int>> a(n + 5, vector<int>(2));
    for (int i = 0; i < n; i++)
    {
        int x, y; cin >> x >> y;
        a[x][y]++;
    }
    
    LL res = 0;
    for (int i = 0; i <= n; i++)
    {
        res += (LL) a[i][0] * a[i][1] * (n - 2);
        if (i == 0 || i == n) continue;
        res += (LL) a[i - 1][0] * a[i][1] * a[i + 1][0];
        res += (LL) a[i - 1][1] * a[i][0] * a[i + 1][1];
    }
    cout << res << endl;
}  

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1; cin >> t;
    while (t--) slove();
    return 0;
}

E

注意到数列是一个公差为 1 的等差数列,首项为 k,那么可以根据等差数列的求和公式得到前 i 项的和,i 的范围为: [1, n]
为了使得前缀和后缀差值最小,可以二分 i 的位置,得到最后一个前缀和 小于等于 后缀和的位置;差值需要取该位置的差值和后一个位置的最小值。

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cmath>
#include <map>
using namespace std;
using LL = long long;
typedef pair<int, int> PII;

void slove()
{
    LL n, k; cin >> n >> k;
    LL t = (LL) n * (2 * k + n - 1) / 2;
    int l = 1, r = n + 1;
    while (l < r)
    {
        int mid = l + r  + 1 >> 1;
        LL pre = (LL) mid * (2 * k + mid - 1) / 2;
        LL suf = t - pre;
        if (pre <= suf) l = mid;
        else r = mid - 1;
    }
    LL res = 1e18;
    LL pre = (LL) l * (2 * k + l - 1) / 2;
    LL suf = t - pre;
    // cout << abs(pre - suf) << endl;
    res = min(res, abs(pre - suf));
    l++;
    pre = (LL) l * (2 * k + l - 1) / 2;
    suf = t - pre;
    res = min(res, abs(pre - suf));
    // cout << abs(pre - suf) << endl;
    cout << res << endl;
} 

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int t = 1; cin >> t;
    while (t--) slove();
    return 0;
}

F

数组 b 可以理解为由数组 a 组成的 n x n 的二维矩阵,第 i 行由 ai....an a1...ai-1 组成。
对于每一个询问 l,r;可以将 l,r 映射到由两个 a 数组组成的新的数组中。
对于 l 到 r 的和,可以使用前缀和。首先可以计算出 l 和 r 位于 b 的第几层,假如不是位于同一层,那么中间的层数的和是由 a 的和组成的。然后就是处理 l 到该层末尾的和,r 到层首的和。

#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
using LL = long long;

LL get_pre(vector<LL>& pre, LL cen, LL x)
{
    int start = x + cen;
    return pre[start] - pre[cen - 1];
}

void slove()
{
    int n, q; cin >> n >> q;
    vector<LL> nums(2 * n + 10);
    vector<LL> pre(2 * n + 10);
    for (int i = 1; i <= n; i++)
    {
        cin >> nums[i];
        nums[i + n] = nums[i];
    }
    
    for (int i = 1; i <= 2 * n; i++)
    {
        pre[i] = pre[i - 1] + nums[i];
    }
    
    
    while (q--)
    {
        LL l, r; cin >> l >> r;
        LL cen_l = ceil(1.0 * l / n);
        LL cen_r = ceil(1.0 * r / n);
        // cout << cen_l << " " << cen_r << endl;
        int cnt = cen_r - cen_l - 1;
        LL res = (LL) max(0, cnt) * pre[n];
        // cout << res << endl;
        l--, r--;
        l %= n, r %= n;
        // cout << l << " " << r << endl;
        if (cen_l == cen_r)
        {
            res += get_pre(pre, cen_l, r) - get_pre(pre, cen_l, l - 1);
            // cout << nums[cen_l + l] <<  endl;
        }
        else
        {
            res += pre[n] - get_pre(pre, cen_l, l - 1) + get_pre(pre, cen_r, r);
        }
        cout << res << endl;
    }
    
}

int main()
{
    int t; cin >> t;
    while (t--) slove();
    return 0;
}

G1

可以将数组的元素 - i,这样对于两个元素如果是连续的子数组的话,那么值就会相同。
证明如下:
对于任意两哥元素 ai aj,另 j - i = k,那么假如 ai 和 aj 满足连续子数组的要求得话,有 aj = ai + k,
ai - i,aj - j = ai + k - j = ai + j - i -j = ai - i。所以当两个元素满足连续子数组的要求,那么减下标将会相等。

对于一个区间需要改变的最小次数等于 len - maxv。(len 表示区间元素个数,maxv 表示区间内满足连续子数组要求的最大元素个数)问题就转变为求区间内最长连续子数组的元素个数。

使用 map 存储每一个元素减下标的个数,使用 multiset 存储个数。对于区间长度 k,可以使用滑动窗口预处理从每一个下标开始,窗口长度为 k 的最大相同元素个数。
先枚举 [1, k),维护出第一个滑动窗口中相等元素个数。然后依次向后移动,增加进入的元素,减去出去的元素。注意:每枚举一个元素,都会向 multiset 中插入个数,但是在插入之前会将该元素对应的值的个数在 multiset 中减去,否则就重复加了。在这里就需要注意 multiset 的用法:在 erase 之前需要保证 multiset 中有这个值,所以可以在操作之前,先插入 n 个 0,不会影响到答案的获取。

代码

#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <map>
#include <set>
using namespace std;
using LL = long long;

void slove()
{
    int n, k, q; cin >> n >> k >> q;
    vector<int> nums(n + 10);
    vector<int> res (n + 10);
    for (int i = 1; i <= n; i++) cin >> nums[i];
    
    map<int, int> mp;
    multiset<int> s;
    for (int i = 1; i <= n; i++) s.insert(0);  // 由于需要先删除,当一个元素没有进入过multiset之前就会为0,那么
    for (int i = 1; i < k; i++)  // 先处理好第一个窗口
    {
        s.erase(s.find(mp[nums[i] - i]));  // 在增加这个个数之前,需要先删除这个个数之前的插入,这样就可以保证不会重复。
        mp[nums[i] - i]++;
        s.insert(mp[nums[i] - i]);  // 增加个数到 multiset 中
    }
    
    for (int i = k; i <= n; i++)
    {
        s.erase(s.find(mp[nums[i] - i]));
        mp[nums[i] - i]++;
        s.insert(mp[nums[i] - i]);
        int p = i - k + 1;
        res[p] = *s.rbegin();
        
        s.erase(s.find(mp[nums[p] - p]));
        mp[nums[p] - p]--;
        s.insert(mp[nums[p] - p]);
    }
    
    while (q--)
    {
        int l, r; cin >> l >> r;
        cout << k - res[l] << endl;
    }
}

int main()
{
    int t; cin >> t;
    while (t--) slove();
    return 0;
}


http://www.kler.cn/a/294264.html

相关文章:

  • A029-基于Spring Boot的物流管理系统的设计与实现
  • 如何向函数模块 FM 中传递 Range 参数
  • 安装SQL server中python和R
  • 批量重命名Excel文件并排序
  • C++ 编程基础(6)作用域 | 6.3、类作用域
  • 【LeetCode】【算法】581. 最短无序连续子数组
  • 字节6面,面爆炸了
  • 智慧公厕技术应用、系统架构、应用功能有哪些?@卓振思众
  • C#中LINQ的Cast<T>与OfType<T>
  • DevOps学习笔记
  • 基于SpringBoot+Vue+MySQL的校园周边美食探索及分享平台
  • 初识jQuery
  • Android 15 新特性快速解读指南
  • 使用bert_base_chinese实现文本语义相似度计算
  • Spring Boot-自定义banner
  • 视频提取字幕的软件有哪些?高效转录用这些
  • react的useRef作用是什么怎么使用
  • Android Camera系列(一):SurfaceView+Camera
  • 数据结构,单向链表
  • 【2024高教社杯全国大学生数学建模竞赛】B题完整解析(含论文、代码分享)
  • 7个 C# 高阶用法详解:从基础到实战
  • 微信小程序实践案例
  • Kafka Broker处于高负载状态(例如消息处理量大或系统资源不足),无法及时响应消费者的请求
  • 智能工厂程序设计 之1 智能工厂都本俱的方面(Facet,Aspect和Respect)即智能依赖的基底Substrate 之1
  • 机械学习—零基础学习日志(概率论总笔记4)
  • JAVA基础:JVM中方法的执行过程和方法的重载,递归,可变参数的含义