STL 自定义sort 前缀和差分练习

公开课第一期

文章目录

A HDU1280 前m大的数

还记得Gardon给小希布置的那个作业么?(上次比赛的1005)其实小希已经找回了原来的那张数表,现在她想确认一下她的答案是否正确,但是整个的答案是很庞大的表,小希只想让你把答案中最大的M个数告诉她就可以了。
给定一个包含N(N<=3000)个正整数的序列,每个数不超过5000,对它们两两相加得到的N*(N-1)/2个和,求出其中前M大的数(M<=1000)并按从大到小的顺序排列。

直接求和sort即可

数据范围不大,注意下输出格式

#include <iostream>
#include <algorithm>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
const ll maxn = 1e7 + 10;

int N, M, arr[3005], sum[maxn], cnt;

int main(){
    ios;
    while (cin >> N >> M){
        for (int i = 1; i <= N; i ++) cin >> arr[i];
        cnt = 1;
        for (int i = 1; i < N; i ++)
            for (int j = i + 1; j <= N; j ++)
                sum[cnt++] = arr[i] + arr[j];
        sort(sum + 1, sum + cnt);
        for (int i = cnt - 1; i > cnt - M; i --)
            cout << sum[i] << ' ';//格式
        cout << sum[cnt - M] << '\n';
    }

    return 0;
}

B HDU1872 稳定排序

大家都知道,快速排序是不稳定的排序方法。
如果对于数组中出现的任意a[i],aj,其中a[i]==a[j],在进行排序以后a[i]一定出现在a[j]之前,则认为该排序是稳定的。

某高校招生办得到一份成绩列表,上面记录了考生名字和考生成绩。并且对其使用了某排序算法按成绩进行递减排序。现在请你判断一下该排序算法是否正确,如果正确的话,则判断该排序算法是否为稳定的。

根据 稳定排序 的定义,自定义sort

编写自定义排序,将排序后应有的输出顺序与给定的输出进行比较,执行规定操作

#include <iostream>
#include <algorithm>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

int N, flag, flagg;
struct node{
    string name;
    int score,num;
}stu[305],test[305];

bool cmp(const node &a, const node &b) {
    return a.score == b.score ? a.num < b.num : a.score > b.score;
}
void out(){
    for (int i = 1; i <= N; i ++)
        cout << stu[i].name << ' ' << stu[i].score << '\n';
}
int main(){
    ios;
    while (cin >> N){
        flag = 0, flagg = 0;
        for (int i = 1; i <= N; i ++) {
            cin >> stu[i].name >> stu[i].score;
            stu[i].num = i;
        }
        sort(stu + 1, stu + N + 1, cmp);
        for (int i = 1; i <= N; i ++) {
            cin >> test[i].name >> test[i].score;
            if (test[i].score != stu[i].score) flag = 1;
            if (test[i].name != stu[i].name) flagg = 1;
        }
        if (flag) cout << "Error\n", out();
        else if (flagg) cout << "Not Stable\n", out();
        else cout << "Right\n";
    }

    return 0;
}

C HDU1234 开门人和关门人

每天第一个到机房的人要把门打开,最后一个离开的人要把门关好。现有一堆杂乱的机房签
到、签离记录,请根据记录找出当天开门和关门的人。

字符串大小比较

字符串大小比较的步骤:

  1. 从左至右一位一位比较,如果相同,则继续下一位,如果不同,则谁的ASCII大谁的字符串就大
  2. 如果比较到其中一者已经结束了,还没有分出大小,则长度长的字符串大

而该题,时间的记录均为标准格式,位数相同,故可直接使用字符串比较。

将每组存入结构体,自定义sort比较即可。注意题目未说明数据范围,数组要开得适中。

#include <iostream>
#include <algorithm>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

int T, N;

struct node{
    string name, st, et;
}arr[100005];
bool cmp1(const node &a, const node &b){
    return a.st < b.st;
}
bool cmp2(const node &a, const node &b){
    return a.et > b.et;
}
int main(){
    ios;
    cin >> T;
    while (T --){
        cin >> N;
        for (int i = 1; i <= N; i ++) cin >> arr[i].name >> arr[i].st >> arr[i].et;
        sort(arr + 1, arr + N + 1, cmp1);
        cout << arr[1].name << ' ';
        sort(arr + 1, arr + N + 1, cmp2);
        cout << arr[1].name << '\n';
    }
    return 0;
}

D HDU1862 EXCEL排序

Excel可以对一组纪录按任意指定列排序。现请你编写程序实现类似功能。

自定义sort

同上,自定义cmp,sort即可

#include <iostream>
#include <algorithm>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

int N, C, cnt;

struct node{
    string num, name;
    int score;
}arr[100005];
bool cmp(const node &a, const node &b){
    return C == 1 ? a.num < b.num : C == 2 ? a.name == b.name ? a.num < b.num : a.name < b.name : a.score == b.score ? a.num < b.num : a.score < b.score;
}
int main(){
    ios;
    cnt = 1;
    while (cin >> N >> C && N){
        for (int i = 1; i <= N; i ++) cin >> arr[i].num >> arr[i].name >> arr[i].score;
        sort(arr + 1, arr + N + 1, cmp);
        cout << "Case " << cnt ++ << ":\n";
        for (int i = 1; i <= N; i ++) cout << arr[i].num << ' '<< arr[i].name <<' '<< arr[i].score <<'\n';
    }
    return 0;
}

E HDU1412 {A} + {B}

给你两个集合,要求{A} + {B}.
注:同一个集合中不会有两个相同的元素.

set

就是最基本的set应用

#include <iostream>
#include <set>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

int n, m, x, flag;
set <int> st;
int main() {
    ios;
    while (cin >> n >> m) {
        for (int i = 0; i < n + m; i++) {
            cin >> x;
            st.insert(x);
        }
        flag = 0;
        for (int i : st) {
            if (flag) cout << " ";
            flag = 1;
            cout << i;
        }
        cout << '\n';
        st.clear();
    }
    return 0;
}

F HDU1263 水果

夏天来了好开心啊,呵呵,好多好多水果
Joe经营着一个不大的水果店.他认为生存之道就是经营最受顾客欢迎的水果.现在他想要一份水果销售情况的明细表,这样Joe就可以很容易掌握所有水果的销售情况了.

map应用

map的基本用法,该题是两个名字对应一个权值,故用pair存名称

注意输出格式

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <map>
#define fs first
#define sc second
using namespace std;
typedef pair<string, string> pss;

int N, M, num, res;
map<pss, int> mp;
string city, name, cd, namee, cnt;

int main() {
    cin >> N;
    while (N--) {
        mp.clear();
        cin >> M;
        for (int i = 1; i <= M; i++) {
            cin >> name >> city >> num;
            if (mp.find(pss(city, name)) != mp.end())
                mp[pss(city, name)] += num;
            else
                mp[make_pair(city, name)] = num;
        }
        for (auto it = mp.begin(); it != mp.end(); it++) {
            cd = it->fs.fs; namee = it->fs.sc; res = it->sc;
            if (cnt != cd) {
                cnt = cd;
                cout << cnt << '\n';
            }
            cout << "   |----" << namee << '(' << res << ')' << '\n';
        }
        if (N) printf("\n");
    }
    return 0;
}

G HYSBZ2761 不重复数字

给出N个数,要求把其中重复的去掉,只保留第一次出现的数。

例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4。

set

一串数组去重后按原序输出,去重我们很容易想到set,但set将自动排序,故我们进行一次判断,将不重复的数存入到数组中,输出数组即可

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <set>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

set <int> st;
int T, n, m, arr[50005], cnt;
int main(){
    ios;
    cin >> T;
    while(T --){
        cin >> n;
        cnt = 1;
        for(int i=0;i<n;i++){
            cin >> m;
            if(st.count(m)==0){
                st.insert(m);
                arr[cnt ++] = m;
            }
        }
        for (int i = 1; i < cnt - 1; i ++) cout << arr[i] << ' ';
        cout << arr[cnt - 1] << '\n';
        st.clear();
    }

    return 0;
}

H 计蒜客T1655 表达式括号匹配

给出一个表达式,该表达式仅由字符()+-以及数字组成。

请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回"YES";否则返回"NO"

直接计数判断即可

#include <iostream>
using namespace std;

string s;
int cnt = 0;
int main(){
    cin >> s;
    for (int i = 0; i < s.size(); i ++){
        if (s[i] == '(') cnt ++;
        if (s[i] == ')') cnt --;
        if (cnt < 0) {
            cout << "NO";
            return 0;
        }
    }
    if (cnt == 0) cout << "YES";
    else cout << "NO";
    return 0;
}

I CSU1588 合并果子

现在有n堆果子,第i堆有ai个果子。现在要把这些果子合并成一堆,每次合并的代价是两堆果子的总果子数。求合并所有果子的最小代价。

优先队列

优先队列,可以保证数字始终有序排列

首先将每个元素压入小根堆,在循环的时候不断的取头上的值,取两个作为最优值(a,b),最后再弹掉。结果就是不断累加两个元素(a,b),最后再把此次的和再压入小根堆.

  • 可以默认大到小排序,可以利用相反数,改为从小到大
  • priority_queue<int, vector, greater >p 实现从小到大
#include <iostream>
#include <queue>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

priority_queue<int, vector<int>, greater<int> >p;
int T, n, a, ans, x, y;

int main() {
    ios;
    cin >> T;
    while (T--) {
        cin >> n;
        ans = 0;
        for (int i = 1; i <= n; i++)
            cin >> a, p.push(a);
        while (p.size() >= 2) {
            x = p.top(); p.pop();
            y = p.top(); p.pop();
            ans += x + y;
            p.push(x + y);
        }
        cout << ans << endl;
        while (!p.empty()) p.pop();
    }
    return 0;
}

J Codeforces Covered Points Count

You are given nn segments on a coordinate line; each endpoint of every segment has integer coordinates. Some segments can degenerate to points. Segments can intersect with each other, be nested in each other or even coincide.

差分前缀和

模板题

#include <iostream>
#include <algorithm>
#include <map>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define fs first
#define sc second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const int maxn = 1e6 + 10;

int N;
pii lr[maxn];
ll arr[maxn], tail, ca[maxn], idx, ans[maxn], l, r;
map <ll, ll> pos, rpos;
void Lisa() {
    arr[0] = -1;
    sort(arr + 1, arr + tail + 1);
    for (int i = 1; i <= tail; i++)
        if (arr[i] != arr[i - 1])
            pos[arr[i]] = ++idx, rpos[idx] = arr[i];
}

int main() {
    ios;
    cin >> N;
    for (int i = 1; i <= N; i++) {
        cin >> l >> r;
        arr[++tail] = l, arr[++tail] = r + 1;
        lr[i] = {l, r};
    }
    Lisa();
    for (int i = 1; i <= N; i++) {
        l = lr[i].fs, r = lr[i].sc;
        ca[pos[l]] += 1; ca[pos[r + 1]] -= 1;
    }
    for (int i = 1; i <= idx; i++) ca[i] += ca[i - 1];
    for (int i = 1; i <= idx - 1; i++) ans[ca[i]] += rpos[i + 1] - rpos[i];
    for (int i = 1; i <= N; i++) cout << ans[i] << ' ';
    cout << '\n';
    return 0;
}

k HDU1209 Ignatius and the Princess IV

“OK, you are not too bad, em… But you can never pass the next test.” feng5166 says.“I will tell you an odd number N, and then N integers. There will be a special integer among them, you have to tell me which integer is the special one after I tell you all the integers.” feng5166 says.“But what is the characteristic of the special integer?” Ignatius asks.“The integer will appear at least (N+1)/2 times. If you can’t find the right integer, I will kill the Princess, and you will be my dinner, too. Hahahaha…” feng5166 says.

Can you find the special integer for Ignatius?

题目:题意就是给你一个奇数个的数列,里面有一个元素一定会出现超过(n+1)/2次,让你输出这个数

读入 直接sort,然后直接输出中间那个数即可

这里用map写一下吧

#include <iostream>
#include <map>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

int n, ans, x;
map <int,int> m;
int main(){
    ios;
    while(cin >> n){
        for(int i = 0;i < n;i ++){
            cin >> x;
            m[x] ++;
            if (m[x] >= (n+1)/2)
                ans = x;
        }
        cout << ans << endl;
        m.clear();
    }
    return 0;
}

L HDU1896 Stones

Because of the wrong status of the bicycle, Sempr begin to walk east to west every morning and walk back every evening. Walking may cause a little tired, so Sempr always play some games this time.
There are many stones on the road, when he meet a stone, he will throw it ahead as far as possible if it is the odd stone he meet, or leave it where it was if it is the even stone. Now give you some informations about the stones on the road, you are to tell me the distance from the start point to the farthest stone after Sempr walk by. Please pay attention that if two or more stones stay at the same position, you will meet the larger one(the one with the smallest Di, as described in the Input) first.

题意 Sempr在一条直线上从左往右走,在他遇到第奇数块石头时,他会将其往前面扔,能扔多远在输入中会给出,而遇到第偶数个石头时不进行处理。当有两个石头在同一位置时,则先处理"射程"(能扔的距离最短)的石头,然后Sempr一直往前走,直到前面已经没有任何石头时,这时候计算Sempr与出发点的距离。

对于样例1的分析:一开始的时候遇到的是第一个石头,他的坐标是1,然后往前扔了5个单位之后,坐标变成6,随后继续往前走,开始遇到第二个石头(坐标是2),忽略,然后继续往前走,又遇到了原来的第一个石头(现在是第三个石头),但是它此时坐标为6,往前扔了5个单位之后,坐标变成11,然后继续往前走,一直走在坐标11时,这时候他遇到的是第四个石头,因此忽略不计。至此,前面已经没有石头了,因此此时离坐标原点的距离为11。

优先队列解决上述问题,先将每个石头的位置及其能够扔的距离封装成一个结构体,然后再根据小根堆的思想重载

优先队列的优先级即可。利用一个bool变量来控制奇偶,奇数时处理,偶数时不处理

#include <iostream>
#include <queue>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;

int T, N;
ll P, D;
bool tmp;
struct node {
    ll pos, dis;
    friend bool operator<(const node &a, const node &b){
        return a.pos == b.pos ? a.dis > b.dis : a.pos > b.pos;
    }
}stu;
priority_queue<node> que;
int main() {
    ios;
    cin >> T;
    while (T--) {
        cin >> N;
        for (int i = 1; i <= N; ++i) {
            cin >> stu.pos >> stu.dis;
            que.push(stu);
        }
        tmp = true;
        while (!que.empty()) {
            stu = que.top(); que.pop();
            if (tmp) {
                stu.pos += stu.dis;
                que.push(stu);
            }
            tmp = !tmp;
        }
        cout << stu.pos << '\n';
    }
    return 0;
}

M HDU1897 SnowWolf’s Wine Shop

After retired from hustacm, Sempr(Liangjing Wang) find a part-time-job in Snowwolf(Wei Xu)'s wine shop. There are different qualities of wine in the shop, and all of which has a rating describing the qualities. All the ratings are larger than 0 and smaller than 1,000,000. Everyday nearly Q people will go to his shop and buy a bottle of wine because of his kindness. Once a customer want an X qualified rating but there are no such one, Sempr will sell him a better one with the smallest rating. But the boss of the shop is Snowwolf, you know, so if no wine has no more than Y qualified ratings better than the customer’s request, Sempr will say sorry to them. Every morning, Xiangsanzi will send N bottles of different or same qualified wine.

multiset模板题

#include <iostream>
#include <algorithm>
#include <set>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

using namespace std;
int T, a, b, c;
int x, tmp = 1;
multiset<int> m;

int main() {
    ios;
    cin >> T;
    while (T--) {
        m.clear();
        cin >> a >> b >> c;
        cout << "Case " << tmp++ << ":" << endl;
        while (a--) {
            cin >> x; m.insert(x);
        }
        while (b--) {
            cin >> x;
            auto it = m.lower_bound(x);
            if (it == m.end() || (c < (*it - x)))
                cout << "-1" << endl;
            else {
                cout << *it <<endl;
                m.erase(it);
            }
        }
    }
    return 0;
}

N Codeforces Alice, Bob and Candies

There are nn candies in a row, they are numbered from left to right from 11 to nn. The size of the ii-th candy is aiai.

Alice and Bob play an interesting and tasty game: they eat candy. Alice will eat candy from left to right, and Bob — from right to left. The game ends if all the candies are eaten.

The process consists of moves. During a move, the player eats one or more sweets from her/his side (Alice eats from the left, Bob — from the right)…

题意:有n颗糖果,A从左往右吃,B从右往左吃,AB交替进行,由A先开始,且每个人吃的都要比上一个人吃的严格多,最后一次除外,吃完结束。输出总步数和两人各吃糖果数量

题目很长也很简单,简单模拟就可实现,方法较多,这里用双端队列写一下。

#include <iostream>
#include <deque>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

int T, n, x, tmpa, tmpb, resa, resb, cnt, flag;
deque <int> dq;
int main(){
    ios;
    cin >> T;
    while (T --){
        resa = 0, resb = 0;
        tmpb = 0, cnt = 0, flag = 0;
        cin >> n;
        while (n --){
            cin >> x;
            dq.push_back(x);
        }
        while(!dq.empty()){
            tmpa = 0;
            while (tmpa <= tmpb){
                tmpa += dq.front();
                dq.pop_front();
                if(dq.empty()){
                    flag = 1;
                    break;
                }
            }
            cnt ++; resa += tmpa; if(flag)break;
            tmpb = 0;
            while (tmpb <= tmpa){
                tmpb += dq.back();
                dq.pop_back();
                if(dq.empty()){
                    flag = 1;
                    break;
                }
            }
            cnt ++; resb += tmpb; if(flag)break;
        }
        cout << cnt << ' ' << resa << ' ' << resb << endl;
    }
    return 0;
}

O. Codeforces Special Elements

Pay attention to the non-standard memory limit in this problem.

In order to cut off efficient solutions from inefficient ones in this problem, the time limit is rather strict. Prefer to use compiled statically typed languages (e.g. C++). If you use Python, then submit solutions on PyPy. Try to write an efficient solution…

题意:给n个数,如果一个数可以表示为某个大于等于2的区间的和,那么他就是特殊元素,问一共有多少个特殊元素.

前缀和转化一下问题.求出前缀和,并在读入将存储n个数转变为存储数x出现的次数(数据量8e3,可开cnt[8e3])。任意大于等于2的区间的和为sum[r]-sum[l],令其为tmp,从计数数组中找出共有多少个特殊元素。虽然是二重循环,但通过break可减少循环次数。并注意防止越界

#include <iostream>
#include <cstring>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

int T, n, x, mx, sum[8005] = {0}, cnt[8005], tmp, res;
int main(){
    ios;
    cin >> T;
    while (T --){
        res = 0, mx = 0;
        memset(cnt, 0, sizeof(cnt));
        cin >> n;
        for (int i = 1; i <= n; i ++){
            cin >> x;
            mx = max(mx, x);
            sum[i] = sum[i - 1] + x;
            cnt[x] ++;
        }
        for (int i = 1; i < n; i ++){
            for (int j = i + 1; j <=n ; j ++){
                tmp = sum[j] - sum[i - 1];
                if(tmp > mx) break;
                if (tmp < 8005 && cnt[tmp] != 0) {
                    res += cnt[tmp];
                    cnt[tmp] = 0;
                }
            }
        }
        cout << res << endl;
    }

    return 0;
}

P HDU1003 Max Sum

Given a sequence a[1],a[2],a[3]…a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.

注意最大有可能为负

#include <iostream>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

int T, n, x, sum[100005], min_idx[100005], mx, ans, l, r, kase = 1;
int main(){
    ios;
    cin >> T;
    while (T --){
        mx = 0, ans = -2e9;
        cin >> n;
        for (int i = 1; i <= n; i ++){
            cin >> x;
            sum[i] = sum [i - 1] + x;
        }
        for(int i = 1;i <= n; i ++){
            min_idx[i] = mx;
            if(sum[i] < sum[mx]) mx = i;
        }
        for(int i = 1; i <= n; i ++)
            if(sum[i] - sum[min_idx[i]] > ans){
                ans = sum[i] - sum[min_idx[i]];
                l = min_idx[i] +1,r = i;
            }
        cout << "Case " << kase ++ << ":\n";
        cout << ans << ' ' << l << ' ' << r << '\n';
        if (T) cout << '\n';
    }
    return 0;
}

差分模板 AcWing 797

输入一个长度为n的整数序列。

接下来输入m个操作,每个操作包含三个整数l, r, c,表示将序列中[l, r]之间的每个数加上c。

请你输出进行完所有操作后的序列。

差分模板

#include <iostream>
using namespace std;
const int N = 100010;
int a[N], ca[N];
int main() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
        ca[i] = a[i] - a[i - 1];
    }
    while (m--) {
        int l, r, c;
        cin >> l >> r >> c;
        ca[l] += c;
        ca[r + 1] -= c;
    }
    for (int i = 1; i <= n; i++) {
        ca[i] += ca[i - 1];
        cout << ca[i] << " ";
    }
    return 0;
}

前缀和应用 洛谷P3406

大东亚海底隧道连接着厦门、新北、博艾、那霸、鹿儿岛等城市,横穿东海,耗资1000亿博艾元,历时15年,于公元2058年建成。凭借该隧道,从厦门可以乘坐火车直达台湾、博艾和日本,全程只需要4个小时。

利用前缀和

对于其中一小段,我们要么全部买纸票,要么全部刷卡。所以我们只需要统计每一小段经过的总次数。

直接思想就是记录每一段要经过的次数,再进行贪心计算。

如果暴力模拟统计的话,会tle。我们很容易想到利用差分前缀和记录

#include <iostream>
#include <cstring>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int N = 100005;
int n, m, arr[N];
long long ca[N], res = 0;
struct node{
    int a, b, c;
}stu[N];
int main() {
    ios;
    memset(ca, 0, sizeof(ca));
    cin >> n >> m;
    cin >> arr[0];
    for (int i = 1; i < m; i++){
        cin >> arr[i];
        ca[min(arr[i - 1], arr[i])] ++;
        ca[max(arr[i - 1], arr[i])] --;
    }
    for (int i = 1; i < n; i ++)
        ca[i] += ca[i - 1];
    for (int i = 1; i < n; i ++){
        cin >> stu[i].a >> stu[i].b >> stu[i].c;
        res += min(ca[i] * stu[i].a, ca[i] * stu[i].b + stu[i].c);
    }
    cout << res;
    return 0;
}

ST表模板 洛谷3865

给定一个长度为 NN 的数列,和 MM 次询问,求出每一次询问的区间内数字的最大值。

输入格式

第一行包含两个整数 N, MN,M ,分别表示数列的长度和询问的个数。

第二行包含 NN 个整数(记为 a_ia**i),依次表示数列的第 ii 项。

接下来 MM行,每行包含两个整数 l_i, r_il**i,r**i,表示查询的区间为 [ l_i, r_i][l**i,r**i]

输出格式

输出包含 MM行,每行一个整数,依次表示每一次询问的结果。

RMQ(区间最值查询问题)

详见链接

#include <algorithm>
#include <cstdio>
#define M 25
#define N 100005
using namespace std;
int n, m, a[N], Log[N], f[N][M];
inline void read(int &x){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    x = s*w;
}
void GetLog() {
    int i;
    Log[1] = 0;
    for (i = 2; i <= n + 1; ++i)
        Log[i] = Log[i / 2] + 1;
}
void RMQ() {
    for (int i = 1; i <= n; ++i)
        f[i][0] = a[i];
    for (int j = 1; (1 << j) <= n; ++j)
        for (i = 1; i + (1 << (j - 1)) <= n; ++i)
            f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
int main() {
    int l, r, i, k, ans;
    read(n), read(m);
    for (i = 1; i <= n; ++i)
        read(a[i]);
    GetLog();
    RMQ();
    for (i = 1; i <= m; ++i) {
        read(l), read(r);
        k = Log[r - l + 1];
        ans = max(f[l][k], f[r - (1 << k) + 1][k]);
        printf("%d\n", ans);
    }
    return 0;
}

倍增ST表 牛客15429

给你一个长为n的序列a和一个常数k

有m次询问,每次查询一个区间[l,r]内所有数最少分成多少个连续段,使得每段的和都 <= k

如果这一次查询无解,输出"Chtholly"

发现贪心可过,这里用贪心写一下

#include <algorithm>
#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int MAX = 1e6 + 5;
int n, m, f[MAX][22];;
ll K, a[MAX], sum[MAX];
int main() {
    cin >> n >> m >> K;
    for (int i = 1; i <= n; i++)
        scanf("%lld", a + i), sum[i] = sum[i - 1] + a[i];
    for (int i = 1; i <= n; i++) {
        int pos = upper_bound(sum + i, sum + n + 1, sum[i - 1] + K) - sum;
        f[i][0] = pos;
    }
    for (int j = 0; j <= 21; j++)
        f[n + 1][j] = n + 1;
    for (int j = 1; j <= 21; j++) {
        for (int i = 1; i <= n; i++)
            f[i][j] = f[f[i][j - 1]][j - 1];
    }
    while (m--) {
        int l, r;
        scanf("%d%d", &l, &r);
        int ans = 0;
        for (int j = 21; j >= 0; j--) {
            if (f[l][j] <= r)
                ans += (1 << j), l = f[l][j];
        }
        if (f[l][0] > r) {
            printf("%d\n", ans + 1);
        } else
            printf("Chtholly\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值