首页 > 其他分享 >8.2 个人赛

8.2 个人赛

时间:2023-08-03 14:47:54浏览次数:31  
标签:PII 8.2 int res long second 个人赛 区间

比赛链接: https://www.luogu.com.cn/contest/122370#description



A - 排列排序

解题思路

根据题意是要去找区间, 并且n的世界范围较大, 所以考虑用双指针去维护; 根据题意我们可以知道排序的最优解就是找到所有最长的区间两端都不相等的区间, 然后把他们直接排序即可; 因为我们下标从小到大遍历, 所以我们最开始遇到的情况要么f[i]=i, 要么f[i]>i; 如果f[i]=i则i++, 如果f[i]>i, 那目前最长的异常区间就是i~f[i], 然后我们设变量j为i, 让j从i开始遍历去找i~f[i]种可能存在的更大的异常边界, 如果f[j]>f[i], 那么就更新最大值, 继续遍历j, 直到到达最大值后答案就可以加上j-i+1, 更新i=j+1 然后继续找下一个最长的异常区间;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int n, m, p;
int f[N];
void solve() {
    cin >> n;
    int res = 0;
    for (int i = 1; i <= n; i++) cin >> f[i];
    int l = 1e9, r = 0;
    int ans = 0;
    for (int i = 1; i <= n; ) {
        if (i == f[i]) i++;
        else {
            int j = i;
            int ans = f[i];
            while (j < ans) {
                j++;
                ans = max(ans, f[j]);
            }
            res += j - i + 1;
            i = j + 1;
        }
    }
    cout << res << endl;
}
signed main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}




B - 计算分数

解题思路

一道比较繁琐的模拟, 因为要进行通分和约分, 还要考虑最后不同情况的输出形式; 当时为了保险就用的字符串进行读入, 后来看题解也可以用scanf("%d/%d",&a,&b)的形式来直接获取值, 代码会短很多, 不过本质都是一个不算难的模拟于是就懒得改了;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int n, m, p;
int a, b, u;
string s;
PII res = { 0,0 };
bool f = false;
int fu = 1;
int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}
void check() {
    b = u;
    u = 0;
    if (res.second == 0) {
        int d = gcd(abs(a), b);
        res.first = a / d;
        res.second = b / d;
    }
    else {
        int c = res.second * b / gcd(res.second, b);
        int c1 = c / res.second;;
        int c2 = c / b;
        res.first *= c1;
        a *= c2;
        res.first += a;
        res.second = c;
        int d = gcd(abs(res.first), res.second);
        res.first /= d, res.second /= d;
    }
}
signed main() {
    cin >> s;
    for (int i = 0; i <= s.size(); i++) {
        if (s[i] >= '0' && s[i] <= '9') {
            u = u * 10 + s[i] - '0';
        }
        else if (s[i] == '+' || s[i] == '-') {
            if (s[i] == '+') fu = 1;
            else fu = -1;
            check();
        }
        else if (s[i] == '/') {
            a = fu * u;
            u = 0;
            f = true;
        }
    }
    check();
    if (res.second == 1) cout << res.first;
    else if (res.first == 0) cout << 0;
    else cout << res.first << '/' << res.second;
    return 0;
}




C - 不成熟的梦想家

解题思路

本次训练赛感觉受益最大的一道题, 因为我对差分的使用方法还停留在修改一段区间的数值, 本题对差分的使用更加灵活; 根据题意, 暴力做法肯定是每次都更新一段区间里的值然后计算边界点的情况; 当时就卡在了怎么优化上, 因为我的思路还是在想怎么去更快地修改一段区间的值, 我想下一次询问的边界点需要用到最新的值去计算, 于是我们的思维就被限制住; 后来看题解发现原来差分还能怎么用:
既然每次都更新区间里的值一定会超时, 并且计算时我们只考虑边界点的情况, 那我们可以把每个点和前一个点的差值存起来, 也就是存差分; 因为我们每次修改一个区间时, 区间内部直接的差分就不变的, 所有就省去了遍历区间的过程, 我们只需要修改边界点的差分即可; 注意有一个坑点, 如果区间的右边界是序列的右边界设为n, 那么修改f[n+1]是没有意义的, 此处可以画图理解; 具体代码如下;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int n, q, s, t, res;
int f[N];
void add(int u) {
    if (f[u] > 0) res -= s * abs(f[u]);
    else if (f[u] < 0) res += t * abs(f[u]);
}
void sub(int u) {
    if (f[u] > 0) res += s * abs(f[u]);
    else if (f[u] < 0) res -= t * abs(f[u]);
}
signed main() {
    cin >> n >> q >> s >> t;
    int a, last = 0;
    for (int i = 0; i <= n; i++) {
        cin >> a;
        f[i] = a - last;
        last = a;
        add(i);
    }
    for (int i = 1; i <= q; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        sub(a);
        if (b + 1 <= n) sub(b + 1);
        f[a] += c;
        f[b + 1] -= c;
        add(a);
        if (b + 1 <= n) add(b + 1);
        cout << res << endl;
    }
    return 0;
}




E - 奶牛排队

解题思路

本题需要找一个区间, 区间里的值都要大于左端点小于右端点, 区间内部不要求单调性, 但是左端点要小于右端点; 题解有一个很巧的做法是用的单调栈; 我们可以遍历1~n来找右端点B, 对于第i个点B, 我们只需要找到B左边第一个大于等于它的的点C, 对于我们要找的左端点A一定在C的右边, 并且A是点C后面的第一个后缀最小值; 根据描述点C和点A都可以用单调栈来求: 找点C是, 每次新枚举到一个点B时,先不将新位置入栈,此时的单调栈顶就是点C位置; 找点C时需要一个下降的单调栈, 而找点A则需要一个上升的单调栈; 点A是上升单调栈中第一个下标大于点C的点; 所有我们单调栈中存的是下标, 找的过程可以用二分实现;
强烈建议用画图理解一下本题;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
int n, m, ans, res;
int f[N];
int up[N], down[N];
int su, sd;
signed main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> f[i];
    for (int i = 1; i <= n; i++) {
        while (su && f[i] <= f[up[su]]) su--;//区间里的点不能和左端点相等, 所有是<=
        while (sd && f[i] > f[down[sd]]) sd--;
        int u = upper_bound(up + 1, up + su + 1, down[sd]) - up;
        if (u != su + 1) {
            ans = i - up[u] + 1;
            res = max(res, ans);
        }
        up[++su] = i;
        down[++sd] = i;
    }
    cout << res;
    return 0;
}




F - Mieszanie kolorów

解题思路

本题不用思考很多, 直接开三个差分数组分别表示该区间是否被涂上某种颜色, 绿色只要满足有黄有蓝无红即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int n, m, res;
int f[N], y[N], bl[N], r[N];
void ins(int a, int b, int c) {
    if (c == 1) {
        y[a]++;
        y[b + 1]--;
    }
    else if (c == 2) {
        bl[a]++;
        bl[b + 1]--;
    }
    else if (c == 3) {
        r[a]++;
        r[b + 1]--;
    }
}
signed main(){
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        ins(a, b, c);
    }
    for (int i = 1; i <= n; i++) {
        r[i] += r[i - 1];
        y[i] += y[i - 1];
        bl[i] += bl[i - 1];
        if (y[i] && bl[i] && !r[i]) res++;
    }
    cout << res;
    return 0;
}




H - Roy&October之取石子II

解题思路

一道博弈论的题目; 对于这种题目我们先考虑必赢的情况, 如果到October回合时石子数为1/2/3, 那么October就一定会赢, 对应的也就是说如果到Roy回合时石子数为4, 那么Roy必输; 根据这个我们得到一个规律, 对于一个数n, 两人都可以将其变成n-1~n-3之间的任意一个数; 如果October想让回合结束后石子数变成4, 那么October可以处在5/6/7的位置上, 如果October在8的位置上, 反而会会使得自己的回合时石子数为4, 也就是说October要是想赢就不能在4的倍数上, 而只要初识的石子数不是4的倍数, October就可以凭借n-1~n-3让Roy处于4的倍数上;

神秘代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 5e7 + 10;
int n, m, idx;
map<int, int> mp;
bool st[N];
signed main(){
    scanf("%d", &n);
    while (n--) {
        scanf("%d", &m);
        if (m % 4) cout << "October wins!" << endl;
        else cout << "Roy wins!" << endl;
    }
    return 0;
}




I - Cow Dance Show S

解题思路

找最小值我们可以用二分的思路二分舞台大小, 在check函数中用小根堆进行模拟判断是否合法即可;

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e4 + 10;
int n, m;
int f[N];
bool check(int u) {
    priority_queue<int, vector<int>, greater<int>> q;
    for (int i = 1; i <= u; i++) {
        q.push(f[i]);
    }
    for (int i = u + 1; i <= n; i++) {
        int t = q.top();
        if (t + f[i] > m) return false;
        else {
            q.pop();
            q.push(t + f[i]);
        }
    }
    return true;
}
signed main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> f[i];
    int l = 1, r = n;
    while (l < r) {
        int mid = l + r>> 1;
        if (check(mid)) {
            r = mid;
        }
        else  l = mid + 1;
    }
    cout << l;
    return 0;
}

标签:PII,8.2,int,res,long,second,个人赛,区间
From: https://www.cnblogs.com/mostimali/p/17603267.html

相关文章

  • 8.1 个人赛
    比赛链接:https://www.luogu.com.cn/contest/122137#descriptionA-BarnEchoesG解题思路一道字符串匹配的题,两个字符串中较小的长度就是匹配字符串最大的长度;然后讲长度从大到小遍历分别找以第一个和第二个为前缀的情况即可找出最大值;神秘代码#include<bits/std......
  • 2023.8.2 翻转卡片游戏
    坑点注意:x不能与任意一张卡片的正面数字相同,包括自己。因此如果一张卡片正反面数字相同,必然不可能是x。暴力由于\(n\leq1000\),因此\(n^2\)暴力是可以过的。遍历每一个\(nums[i]\),判断其正反面是否相同,相同则跳过,不相同则进一步检验。分为两种情况,一是取\(fronts[i]\),另一种是......
  • 8.2做题记录
     1#include<bits/stdc++.h>2usingnamespacestd;3structnode{4intx,y,z,s;5}f[1005];6inta[4],l,ans,dp[1005];7boolcmp(nodec,noded)8{9returnc.x<=d.x;10}11boolbig(intx,inty)12{13returnx>y;1......
  • shell 8.2
    特殊变量:$0获取脚本文件名,以及脚本路径$n获取shell的第n个参数,n在1~9之间$#获取参数的总个数$*获取shell脚本的所有参数(接受整体字符串)$@获取shell脚本的所有参数(接受单个字符串)一些语法:-ne不等于 ......
  • 8.2
    以上是新浪微博中一奇葩贴:“我出生于1988年,直到25岁才遇到4个数字都不相同的年份。”也就是说,直到2013年才达到“4个数字都不相同”的要求。本题请你根据要求,自动填充“我出生于y年,直到x岁才遇到n个数字都不相同的年份”这句话。输入格式:输入在一行中给出出生年份y和目标年份......
  • 2023.8.2
    今天去把之前学的SROP的东西从头梳理了一遍,然后记到了笔记本上,记完之后,我感觉基本上这一块的内容也算是彻底搞明白了。明天开始看花式栈溢出,可能之后还有别的事情要忙,我尽量每天都能花一些时间在网安的学习上。......
  • 暑假集训D9 2023.8.2 补题
    A.「EZEC-10」排列排序给你一个长度为\(n\)的排列\(p_1,p_2,\cdots,p_n\)。你需要把它排序。每次可以花区间长度,即\(r-l+1\)的代价,选择排列中的任意一段区间\([l,r]\),并将\([l,r]\)从小到大排序。现在你可以让他进行若干次这个操作,直到\(p\)中元素的值从\(1\)到......
  • [解题报告] 2023.8.2 dp专题练习赛
    比赛链接:Link[团队私有]T1:https://www.cnblogs.com/SXqwq/p/17600671.htmlT2:https://www.cnblogs.com/SXqwq/p/17601007.htmlT3:完全背包板子T4:https://www.cnblogs.com/SXqwq/p/17601622.html......
  • 8.2 后记
    T1简单的最短路到终点时不用等红灯,不然会挂40ptT2记\(f(i,j)\)表示跳到\((i,j)\)最少使用的体力。那么转移就是枚举上一个位置然后加上曼哈顿距离求最小值。考虑优化,我们注意到如果转移都在左上的话坐标正负的贡献是固定的,所以可以使用数据结构维护。先按照一维扫描线......
  • 8.2
    前几天因为家里有事导致任务未能按时完成,索性今天将kali虚拟机安装完成,重看了一遍学长的文档发现系统需要使用Python语言决定先掌握Python后再考虑下一步编写代码,之前国赛搭的环境有些许问题所以今天全部删除重新思考一下怎么安装。同时打算将《网络是怎样连接的》这本书的阅读穿......