NEU_Train_Camp_2020_基础数据结构


title: NEU_Train_Camp_2020_基础数据结构
date: 2020-07-13 21:13:03
tags:

  • c++
    categories:
  • New
    cover:

基础数据结构

A - Web Navigation

POJ-1028

#include <string>
#include <iostream>
#include <stack>

using namespace std;

void clear(stack<string> &a)
{
    while (!a.empty())
        a.pop();
}

int main(void)
{
    stack<string> forw, bac;
    string cur = "http://www.acm.org/";
    string oper;
    while (cin >> oper and oper != "QUIT")
    {
        if (oper == "VISIT")
        {
            clear(forw);
            bac.push(cur);
            cin >> cur;
            cout << cur << endl;
        }
        else if (oper == "BACK")
        {
            if (bac.empty())
                cout << "Ignored" << endl;
            else
            {
                forw.push(cur);
                cur = bac.top();
                bac.pop();
                cout << cur << endl;
            }
        }
        else
        {
            //FORWARD
            if (forw.empty())
                cout << "Ignored" << endl;
            else
            {
                bac.push(cur);
                cur = forw.top();
                forw.pop();
                cout << cur << endl;
            }
        }
    }
    return 0;
}

B - 简单计算器

HDU 1237

我吐了我吐了我吐了,wa了一上午,我吐了我吐了我吐了

#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>

using namespace std;

int main(void)
{
    stack<double> num;
    string in;
    while (getline(cin, in))
    {
        char op = '!';
        if (in.size() == 1 && in[0] == '0')
            break;
        for (size_t i = 0; i < in.size(); i++)
        {
            if (in[i] == ' ')
                continue;
            if (isdigit(in[i]))
            {
                double n = in[i] - '0';
                for (size_t j = i + 1; j < in.size(); j++)
                {
                    if (isdigit(in[j]))
                    {
                        n = n * 10 + in[j] - '0';
                        i = j + 1;
                    }
                    else
                        break;
                }
                if (op == '!')
                    num.push(n * 1.0);
                else
                {
                    double t;
                    switch (op)
                    {
                    case '+':
                        num.push(n);
                        break;
                    case '-':
                        num.push(-n);
                        break;
                    case '*':
                        t = num.top();
                        num.pop();
                        num.push(t * n);
                        break;
                    case '/':
                        t = num.top();
                        num.pop();
                        num.push(t / n);
                        break;
                    default:
                        break;
                    }
                    op = '!';
                }
            }
            else
            {
                op = in[i];
            }
        }
        double ans = 0;
        while (!num.empty())
        {
            ans += num.top();
            num.pop();
        }
        // cout << fixed << setprecision(2) << ans << endl;  //G++交上去wa , C++ 交上去ac ,vjudge平台
        printf("%.2lf
", ans);
    }
    return 0;
}

C - Catch That Cow

POJ 3278

直接bfs,这简单题应该放在第一场第一题(逃)

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>

using namespace std;
int n, k;
bool vis[100002];

bool isLegal(pair<int, int> t)
{
    if (0 <= t.first and t.first <= 100000 and !vis[t.first])
        return true;
    return false;
}

int bfs(int s)
{
    queue<pair<int, int> > que;
    que.push(make_pair(s, 0));
    vis[s] = true;
    while (!que.empty())
    {
        pair<int, int> f = que.front();
        que.pop();
        if (f.first == k)
        {
            return f.second;
        }
        pair<int, int> t = f;
        --t.first;
        if (isLegal(t))
        {
            vis[t.first] = true;
            t.second++;
            que.push(t);
        }
        t = f;
        t.first++;
        if (isLegal(t))
        {
            vis[t.first] = true;
            t.second++;
            que.push(t);
        }
        t = f;
        t.first *= 2;
        if (isLegal(t))
        {
            vis[t.first] = true;
            t.second++;
            que.push(t);
        }
    }
    return -1;
}

int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    cin >> n >> k;
    cout << bfs(n) << endl;
    return 0;
}

D - Team Queue

HDU 1387 && UVa 540

使用map对队伍进行分组,一个队伍对应一个value ... 当然unordered_map更快,奈何hdu,poj都不支持

常数时间的插入删除,使用std::list<int> 模拟队列

vector<list<int>::iterator>存每个队伍,在队列中最后一个成员的位置.

pop元素是该队伍在队列中的唯一一个元素,要更新该队伍的迭代器为end()
之前我这里没有注意,re了

注意:list进行pop后,指向的迭代器会失效 , 所以re了,而不是wa了

#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#include <map>
#include <list>
using namespace std;
int main(void)
{
    list<int> que;
    map<int, int> vis;
    vector<list<int>::iterator> pos;
    int count = 1;
    int t;
    while (scanf("%d", &t))
    {
        if (t == 0)
            break;
        que.clear();
        vis.clear();
        pos.clear();
        pos.resize(t);
        fill(pos.begin(), pos.end(), que.end());
        printf("Scenario #%d
", count++);
        for (size_t i = 0; i < t; i++)
        {
            int n;
            scanf("%d", &n);
            for (int j = 0; j < n; j++)
            {
                int in;
                scanf("%d", &in);
                vis[in] = i + 1;
            }
        }
        char op[100];
        while (scanf("%s", op) and op[0] != 'S')
        {
            if (op[0] == 'D')
            {
                printf("%d
", que.front());
                if (pos[vis[que.front()] - 1] == que.begin()) //这里re了
                    pos[vis[que.front()] - 1] = que.end();
                que.pop_front();
            }
            else
            {
                int in;
                scanf("%d", &in);
                int temp = vis[in] - 1;
                list<int>::iterator nowp = pos[temp];
                if (nowp == que.end())
                    pos[temp] = que.insert(nowp, in);
                else
                    pos[temp] = que.insert(++nowp, in);
            }
        }
        printf("
");
    }
    return 0;
}

不完全总结迭代器失效

  • 序列式容器
    • 内存重新分配时 , 所有的迭代器都将失效
    • 删除当前的iterator会使后面所有元素的iterator都失效
      • insert() erase()
  • 关联式容器
    • 被删除的元素的迭代器失效

E - Bad Hair Day

POJ 3250

单调栈

最开始两层循环暴力,tle

看了题解使用了单调栈

我原来想的是每头牛最多能看见他右边几头牛 , 单调栈代表的思想是每头牛能被他左边最多几头牛看见,一头牛入栈时,栈内元素数量就是能看见他的牛的数量.

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>

using namespace std;

int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int n;
    cin >> n;
    long long ans(0);
    stack<int> s;
    int h;
    cin >> h;
    s.push(h);
    for (int i = 1; i < n; i++)
    {
        cin >> h;
        while (!s.empty() and s.top() <= h)
        {
            s.pop();
        }
        ans += s.size();
        s.push(h);
    }
    cout << ans;
    return 0;
}

单调栈经典例题 84.柱状图中最大的矩形

与上面奶牛那个不太一样

class Solution
{
public:
    int largestRectangleArea(vector<int> &heights)
    {
        vector<pair<int, int>> touch(heights.size());
        stack<int> s;
        for (size_t i = 0; i < heights.size(); i++)
        {
            //入栈时确定左边界,出栈确定右边界
            while (!s.empty() and heights[i] <= heights[s.top()])
            {
                touch[s.top()].second = i - 1;
                s.pop();
            }
            touch[i].first = s.empty() ? 0 : s.top() + 1;
            s.push(i);
        }
        while (!s.empty())
        {
            touch[s.top()].second = heights.size() - 1;
            s.pop();
        }
        int tmax = 0;
        for (size_t i = 0; i < touch.size(); i++)
        {
            tmax = max(tmax, (touch[i].second - touch[i].first + 1) * heights[i]);
        }
        return tmax;
    }
	//另一种写法,不够优雅
    int largestRectangleArea1(vector<int> &heights)
    {
        vector<pair<int, int>> res(heights.size());
        stack<int> s;
        for (int i = 0; i < heights.size(); i++)
        {
            while (!s.empty() and heights[i] <= heights[s.top()])
                s.pop();
            res[i].first = s.empty() ? -1 : s.top();
            s.push(i);
        }
        while (!s.empty())
        {
            s.pop();
        }
        for (int i = heights.size() - 1; i >= 0; i--)
        {
            while (!s.empty() and heights[i] <= heights[s.top()])
                s.pop();
            res[i].second = s.empty() ? heights.size() : s.top();
            s.push(i);
        }
        int tmax = 0;
        for (int i = 0; i < res.size(); i++)
        {
            if ((res[i].second - res[i].first - 2 + 1) * heights[i] > tmax)
                tmax = (res[i].second - res[i].first - 2 + 1) * heights[i];
        }
        return tmax;
    }
};

F - How Many Tables

简单的并查集

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>

using namespace std;
int n, m;
int fa[1010];

int findfa(int a)
{
    if (fa[a] == a)
    {
        return a;
    }
    else
    {
        return fa[a] = findfa(fa[a]);
    }
}

void unio(int a, int b)
{
    a = findfa(a);
    b = findfa(b);
    if (a != b)
        fa[b] = a;
}

void init()
{
    for (size_t i = 1; i <= n; i++)
    {
        fa[i] = i;
    }
}
int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        cin >> n >> m;
        init();
        for (int i = 0; i < m; i++)
        {
            int a, b;
            cin >> a >> b;
            unio(a, b);
        }
        int ans(0);
        for (int i = 1; i <= n; i++)
        {
            if (i == fa[i])
                ans++;
        }
        cout << ans
        << endl;
    }
    return 0;
}

G - 畅通工程

HDU 1863

没思路.

最小生成树, 挑战程序设计竞赛 p105

prim+邻接表+优先队列 _没太理解

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define mp(a, b) make_pair(a, b)
using namespace std;
using p = pair<int, int>;
vector<p> edge[102];
bool vis[102];
int n, m;

void prim()
{
    priority_queue<p, vector<p>, greater<p>> que;
    que.push(mp(0, 1));
    int ans = 0;
    while (!que.empty())
    {
        p u = que.top();
        que.pop();
        if (!vis[u.second])
        {
            vis[u.second] = true;
            ans += u.first;
            for (int i = 0; i < edge[u.second].size(); i++)
            {
                p v = edge[u.second][i];
                if (!vis[v.second])
                {
                    que.push(v);
                }
            }
        }
    }
    
    //binary_search要求数组有序,故使用find
    if (find(vis + 1, vis + m + 1, false) == vis + m + 1)
        cout << ans << endl;
    else
        cout << '?' << endl;
}

int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    while (cin >> n >> m and n != 0)
    {
        for (size_t i = 0; i <= m; i++)
        {
            edge[i].clear();
        }
        memset(vis, 0, sizeof(vis));
        for (size_t i = 0; i < n; i++)
        {
            int a, b, c;
            cin >> a >> b >> c;
            edge[a].push_back(mp(c, b));
            edge[b].push_back(mp(c, a));
        }
        prim();
    }
    return 0;
}

网上抄的

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
using namespace std;

#define INF 0x3f3f3f3f
#define MAXN 120
typedef long long ll;
int n, q;
int V;
int res;
int mincost[MAXN];
int used[MAXN];

struct edge
{
    int to, cost;
    edge() {}
    edge(int to, int cost) : to(to), cost(cost) {}
};
vector<edge> G[MAXN]; //存放从i出发的边

typedef pair<int, int> P; //first存放距离,second存放节点
priority_queue<P, vector<P>, greater<P>> que;

void prim()
{
    memset(used, 0, sizeof(used));
    fill(mincost, mincost + V, INF);
    res = 0;
    que.push(P(0, 0));

    while (!que.empty())
    {
        P p = que.top();
        que.pop();
        int v = p.second, d = p.first;
        if (used[v])
            continue;
        used[v] = 1;
        res += d;

        for (int i = 0; i < G[v].size(); i += 1)
        {
            edge e = G[v][i];
            if ((mincost[e.to] > e.cost) && !used[i])
            {
                mincost[e.to] = e.cost;
                que.push(P(mincost[e.to], e.to));
            }
        }
    }
    printf("%d
", res);
}

int main()
{
    while (scanf("%d", &n) != EOF)
    {
        memset(G, 0, sizeof(G)); //每次要初始化啊
        for (int i = 0; i < n; i += 1)
        {
            for (int j = 0; j < n; j += 1)
            {
                int a;
                cin >> a;
                G[i].push_back(edge(j, a));
            }
        }
        cin >> q;
        for (int i = 0; i < q; i += 1)
        {
            int a, b;
            cin >> a >> b;
            G[a - 1][b - 1].cost = G[b - 1][a - 1].cost = 0;
        }
        V = n;
        prim();
    }
    return 0;
}

H - 食物链

POJ - 1182

我称之为并查集的进阶

挑战程序设计竞赛 p88

POJ - 1182: 食物链 (并查集)

这种比带权那种解法更容易理解,但显著的缺点就是废空间;

使用cin会tle

#include <cstdio>
#include <iostream>
using namespace std;
int n, k;
int fa[150014];
void init()
{
    for (int i = 1; i <= 3 * n; i++)
    {
        fa[i] = i;
    }
}

int findfa(int a)
{
    if (fa[a] == a)
        return a;
    else
        return fa[a] = findfa(fa[a]);
}

void unio(int a, int b)
{
    a = findfa(a);
    b = findfa(b);
    if (a != b)
        fa[a] = b;
}

bool judge(int a, int b)
{
    return findfa(a) == findfa(b);
}

int main(void)
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    // cin >> n >> k;
    scanf("%d %d", &n, &k);
    int ans = 0;
    init();
    while (k--)
    {
        int d, x, y;
        scanf("%d %d %d", &d, &x, &y);
        // cin >> d >> x >> y;  // tle
        if (x > n || y > n || (d == 2 && x == y))
            ans++;
        else
        {
            //若D=1,则表示X和Y是同类。
            if (d == 1)
            {
                if (judge(x, y + n) || judge(y, x + n)) //判断是否为同类,不是直接去判断,而是没有吃与被吃的关系就是同类
                    ans++;
                else
                {
                    unio(x, y);
                    unio(x + n, y + n);
                    unio(x + 2 * n, y + 2 * n);
                }
            }
            else
            { //若D=2,则表示X吃Y。
                if (judge(x, y) || judge(y, x + n)) //x,y是同类 或者y吃x
                    ans++;
                else
                {
                    unio(x, y + n);
                    unio(x + n, y + 2 * n);
                    unio(x + 2 * n, y);
                }
            }
        }
    }
    printf("%d
", ans);
    // cout << ans << endl;
    return 0;
}

带权并查集

https://blog.csdn.net/Cfreezhan/article/details/8767413

https://zhuanlan.zhihu.com/p/104581351

我???

#include <cstdio>
const int MAX = 50005;

int parent[MAX];
int rank[MAX];

void MakeSet(int x)
{
    parent[x] = x;
    rank[x] = 0;
}

//查找x的集合,回溯时压缩路径,并修改x与father[x]的关系
int FindSet(int x)
{
    if (x == parent[x])
        return x;
    else
    {
        //rank[x] = (rank[x] + rank[parent[x]]) % 3; // !!!这么写会wa
        //return parent[x] = FindSet(parent[x]);  //wa
        int t = parent[x];
        parent[x] = FindSet(parent[x]);
        rank[x] = (rank[x] + rank[t]) % 3;
        return parent[x]; // 这样就ac了
    }
}

//合并x,y所在的集合
void Union(int x, int y, int d)
{
    int xRoot = FindSet(x);
    int yRoot = FindSet(y);
    //将集合x所在合并到y所在集合上
    parent[xRoot] = yRoot;
    //更新x的根与x的父节点的关系
    rank[xRoot] = (rank[y] - rank[x] + 3 + d) % 3;
}

int main()
{
    int ans = 0;
    int n, k, x, y, d, xRoot, yRoot;
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i)
        MakeSet(i);
    while (k--)
    {
        scanf("%d%d%d", &d, &x, &y);
        //如果x或y比n大,或x吃x,是假话
        if (x > n || y > n || (d == 2 && x == y))
        {
            ans++;
        }
        else
        {
            xRoot = FindSet(x);
            yRoot = FindSet(y);
            //如果x,f的父节点相同 ,那么可以判断给出的关系是否正确的
            if (xRoot == yRoot)
            {
                if ((rank[x] - rank[y] + 3) % 3 != d - 1)
                    ans++;
            }
            else
            {
                //否则合并x,y
                Union(x, y, d - 1);
            }
        }
    }
    printf("%d
", ans);
    return 0;
}

I - Snowflake Snow Snowflakes

POJ 3349

使用set<vector<int> >会tle,poj又用不了unordered_set

自建hash表

了解哈希表概念后,看题解 难度不高

纯c , 记得用gcc提交 , 用 c 提交会 ce

事实证明,用纯c不会更快,也不会更小 (逃)

20200723 2336 48
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

struct node
{
    int a[6];
};

struct node hash[15000][1000];
int hashLen[15000];

int getHash(struct node *p)
{
    long long t = 0;
    int i;
    for (i = 0; i < 6; i++)
    {
        t += p->a[i];
    }
    return (int)(t % 14997);
}

int cmp(const void *a, const void *b)
{
    return *(int *)(a) - *(int *)(b);
}

int isSame(struct node j, struct node k)
{
    qsort(j.a, 6, sizeof(int), cmp);
    qsort(k.a, 6, sizeof(int), cmp);
    int i;
    for (i = 0; i < 6; i++)
    {
        if (j.a[i] != k.a[i])
            return 0;
    }
    return 1;
}

int hashInsert(struct node *t)
{
    int tkey = getHash(t);
    int i;
    for (i = 0; i < hashLen[tkey]; i++)
    {
        if (isSame(*t, hash[tkey][i]))
        {
            return 0;
        }
    }
    hash[tkey][hashLen[tkey]++] = *t;
    return 1;
}

int main()
{
    int t;
    scanf("%d", &t);
    struct node tmp;
    int i;
    for (i = 0; i < t; i++)
    {
        int j;
        for (j = 0; j < 6; j++)
        {
            scanf("%d", &tmp.a[j]);
        }
        if (!hashInsert(&tmp))
        {
            printf("Twin snowflakes found.");
            return 0;
        }
    }
    printf("No two snowflakes are alike.
");
    return 0;
}

记录下ce原因

Main.c
F:	emp21837784.264775Main.c(34) : error C2143: syntax error : missing ';' before 'type'
F:	emp21837784.264775Main.c(35) : error C2065: 'i' : undeclared identifier
F:	emp21837784.264775Main.c(35) : error C2065: 'i' : undeclared identifier
F:	emp21837784.264775Main.c(35) : error C2065: 'i' : undeclared identifier
F:	emp21837784.264775Main.c(37) : error C2065: 'i' : undeclared identifier
F:	emp21837784.264775Main.c(37) : error C2065: 'i' : undeclared identifier
F:	emp21837784.264775Main.c(62) : error C2143: syntax error : missing ';' before 'type'
F:	emp21837784.264775Main.c(63) : error C2143: syntax error : missing ';' before 'type'
F:	emp21837784.264775Main.c(64) : error C2065: 'i' : undeclared identifier
F:	emp21837784.264775Main.c(64) : error C2065: 'i' : undeclared identifier
F:	emp21837784.264775Main.c(64) : error C2065: 'i' : undeclared identifier
F:	emp21837784.264775Main.c(69) : error C2065: 'tmp' : undeclared identifier
F:	emp21837784.264775Main.c(69) : error C2224: left of '.a' must have struct/union type
F:	emp21837784.264775Main.c(71) : error C2065: 'tmp' : undeclared identifier

poj用的是远古的vc++

Visual Studio only supports C89. That means that all of your variables must be declared before anything else at the top of a function.

小改一下,就ac了

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

struct node
{
    int a[6];
};

struct node hash[15000][1000];
int hashLen[15000];

int getHash(struct node *p)
{
    long long t = 0;
    int i;
    for (i = 0; i < 6; i++)
    {
        t += p->a[i];
    }
    return (int)(t % 14997);
}

int cmp(const void *a, const void *b)
{
    return *(int *)(a) - *(int *)(b);
}

int isSame(struct node j, struct node k)
{
    int i;
    qsort(j.a, 6, sizeof(int), cmp);
    qsort(k.a, 6, sizeof(int), cmp);
    for (i = 0; i < 6; i++)
    {
        if (j.a[i] != k.a[i])
            return 0;
    }
    return 1;
}

int hashInsert(struct node *t)
{
    int tkey = getHash(t);
    int i;
    for (i = 0; i < hashLen[tkey]; i++)
    {
        if (isSame(*t, hash[tkey][i]))
        {
            return 0;
        }
    }
    hash[tkey][hashLen[tkey]++] = *t;
    return 1;
}

int main()
{
    int t;
    int i;
    int j;
    struct node tmp;
    scanf("%d", &t);
    for (i = 0; i < t; i++)
    {
        for (j = 0; j < 6; j++)
        {
            scanf("%d", &tmp.a[j]);
        }
        if (!hashInsert(&tmp))
        {
            printf("Twin snowflakes found.");
            return 0;
        }
    }
    printf("No two snowflakes are alike.
");
    return 0;
}

J - Power Strings

最小循环节若存在,则其长度等于len-next[len],证明

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
int Next[1000010];
using namespace std;

int getNext(string &a)
{
    Next[0] = -1;
    int i = 0, j = -1;
    while (i < a.length())
    {
        if (j == -1 or a[i] == a[j])
            Next[++i] = ++j;
        else
            j = Next[j];
    }
    return Next[a.length()];
}

int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    string a;
    while (cin >> a and a[0] != '.')
    {
        int n = a.length();
        int x = n - getNext(a);
        if (n % x == 0) // 若有解,那么最短循环节长度为 x = n - nex[n] 。
        {
            cout << n / x
                 << endl;
        }
        else
        {
            cout << 1 << endl;
        }
    }
    return 0;
}

kmp模板

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
int pnext[2000000];
using namespace std;

void getNext(string &str)
{
    pnext[0] = -1;
    int j = 0, k = -1;
    while (j < str.length() - 1)
    {
        if (k == -1 or str[j] == str[k])
        {
            pnext[++j] = ++k;
        }
        else
        {
            k = pnext[k];
        }
    }
}

string kmp(string &s, string &patten)
{
    int i = 0, j = 0;
    while (i < s.length())
    {
        if (j == -1 or s[i] == patten[j])
        {
            ++i, ++j;
        }
        else
        {
            j = pnext[j];
        }

        if (j == patten.length())
        {
            return s.substr(i - j, j);
            // j = pnext[j];    //继续寻找
        } 
    }
    return "";  
}

int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    string s = "abbbadabaabcabadba";
    string pattern = "abaabcaba";
    getNext(pattern);
    cout << kmp(s, pattern);
    return 0;
}

K - A Simple Problem with Integers

此题删掉了

L - Sliding Window

POJ 2823

单调队列

OI WIKI单调队列介绍

c++ ac ,g++ wa ,太诡异了

题解的代码g++提交上去就ac

诡异,诡异 , 对数组的随机访问很耗时吗?poj g++的诡异

#include <vector>
#include <deque>
#include <cstdio>

using namespace std;
vector<int> arr;
int n, k;
void slidingMin()
{
    deque<int> que;
    for (int i = 0; i < k; i++)
    {
        while (!que.empty() && arr[que.back()] >= arr[i])
            que.pop_back();
        que.push_back(i);
    }
    printf("%d", arr[que.front()]);
    for (int i = k; i < n; i++)
    {
        while (!que.empty() && i - que.front() >= k)
            que.pop_front();
        while (!que.empty() && arr[que.back()] >= arr[i])
            que.pop_back();
        que.push_back(i);
        printf(" %d", arr[que.front()]);
    }
    printf("
");
}
void slidingMax()
{
    deque<int> que;
    for (size_t i = 0; i < k; i++)
    {
        while (!que.empty() && arr[que.back()] <= arr[i])
            que.pop_back();
        que.push_back(i);
    }
    printf("%d", arr[que.front()]);
    for (size_t i = k; i < n; i++)
    {
        while (!que.empty() && i - que.front() >= k)
            que.pop_front();
        while (!que.empty() && arr[que.back()] <= arr[i])
            que.pop_back();
        que.push_back(i);
        printf(" %d", arr[que.front()]);
    }
}
int main(void)
{
    scanf("%d %d", &n, &k);
    arr.resize(n);
    for (size_t i = 0; i < n; i++)
    {
        scanf("%d", &arr[i]);
    }
    slidingMin();
    slidingMax();
    return 0;
}

M - Feel Good

前缀和+单调栈

https://blog.nowcoder.net/n/7adc5e27098442cda1e6d31677495ed1

我太**气了 , tle 我明白,scanf and printfcin and cout快 (c++11以上,关闭同步,应该相差不大)

wa我实在是不明白,再也不用pair

先放ac版

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
using namespace std;

long long in[100100];
long long sum[100100];
int l[100100], r[100100];
int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int t;
    scanf("%d", &t);
    sum[0] = 0;
    stack<int> s;
    for (int i = 1; i <= t; i++)
    {
        scanf("%d", &in[i]);
        sum[i] = sum[i - 1] + in[i];
    }
    for (int i = 1; i <= t; i++)
    {
        while (!s.empty() && in[i] <= in[s.top()])
        {
            // touch[s.top()].second = i - 1;
            r[s.top()] = i - 1;
            s.pop();
        }
        l[i] = s.empty() ? 1 : s.top() + 1;
        s.push(i);
    }
    while (!s.empty())
    {
        // touch[s.top()].second = t;
        r[s.top()] = t;
        s.pop();
    }
    long long tmax = 0;
    int rl, rr;
    for (int i = 1; i <= t; i++)
    {
        long long res = (in[i]) * (sum[r[i]] - sum[l[i] - 1]);
        if (tmax <= res)
        {
            tmax = res;
            rl = l[i];
            rr = r[i];
        }
    }
    printf("%lld
", tmax);
    printf("%d %d
", rl, rr);
    return 0;
}

tle版

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#define p pair<int, int>
using namespace std;

long long in[100100];
long long sum[100100];
p touch[100100];
int l[100100], r[100100];
int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int t;
    cin >> t;
    sum[0] = 0;
    stack<int> s;
    for (int i = 1; i <= t; i++)
    {
        cin >> in[i];
        sum[i] = sum[i - 1] + in[i];
    }
    for (int i = 1; i <= t; i++)
    {
        while (!s.empty() && in[i] <= in[s.top()])
        {
            // touch[s.top()].second = i - 1;
            r[s.top()] = i - 1;
            s.pop();
        }
        l[i] = s.empty() ? 1 : s.top() + 1;
        s.push(i);
    }
    while (!s.empty())
    {
        // touch[s.top()].second = t;
        r[s.top()] = t;
        s.pop();
    }
    long long tmax = 0;
    int rl, rr;
    for (int i = 1; i <= t; i++)
    {
        long long res = (in[i]) * (sum[r[i]] - sum[l[i] - 1]);
        if (tmax <= res)
        {
            tmax = res;
            rl = l[i];
            rr = r[i];
        }
    }
    printf("%lld
", tmax);
    printf("%d %d
", rl, rr);
    return 0;
}

wa版

#include <iostream>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#define p pair<int, int>
using namespace std;

long long in[100100];
long long sum[100100];
int main(void)
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    int t;
    cin >> t;
    vector<p> touch(t + 1);
    sum[0] = 0;
    stack<int> s;
    for (int i = 1; i <= t; i++)
    {
        cin >> in[i];
        sum[i] = sum[i - 1] + in[i];
    }
    for (int i = 1; i <= t; i++)
    {
        while (!s.empty() && in[i] <= in[s.top()])
        {
            touch[s.top()].second = i - 1;
            s.pop();
        }
        touch[i].first = s.empty() ? 1 : s.top() + 1;
        s.push(i);
    }
    while (!s.empty())
    {
        touch[s.top()].second = t;
        s.pop();
    }
    long long tmax = 0, l, r;
    for (int i = 1; i <= t; i++)
    {
        long long res = (in[i]) * (sum[touch[i].second] - sum[touch[i].first - 1]);
        if (tmax <= res)
        {
            tmax = res;
            l = touch[i].first;
            r = touch[i].second;
        }
    }
    printf("%I64d
", tmax);
    printf("%d %d
", l, r);
    return 0;
}
原文地址:https://www.cnblogs.com/Delta2019/p/13369664.html