A.Fast Food Restaurant

题意:一共有3种物品,每种物品每次只能取一个或零个,问一共能组成多少种组合

题解:取一个、两个、三个,一共就7种情况讨论一下即可

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
void solve()
{
    int a[3];
    for (int i = 0; i < 3; i++)
        scanf("%d", &a[i]);
    sort(a, a + 3, greater<int>());
    int ans = 0;
    if (a[0])
        a[0]--, ans++;
    if (a[1])
        a[1]--, ans++;
    if (a[2])
        a[2]--, ans++;
    if (a[0] && a[1])
        a[0]--, a[1]--, ans++;
    if (a[0] && a[2])
        a[0]--, a[2]--, ans++;
    if (a[1] && a[2])
        a[1]--, a[2]--, ans++;
    if (a[0] && a[1] && a[2])
        a[0]--, a[1]--, a[2]--, ans++;
    printf("%d\n", ans);
}
int main()
{
    int t;
    for (scanf("%d", &t); t >= 1; t--)
        solve();
    return 0;
}

B.Different Rules

题意:一个人参加两场比赛,一共n个人,第一次第x名,第二次y名,询问他两场的名次相加最高能取得第几名以及最低能取得第几名

题解:对于最低的名次,只要将第一次的第1名与第二次的第x+y-1名、第一次的第2名与第二次的第x+y-2名...这样就能构造出x+y-1个x+y分的人,他的最低名次就是x+y-1。对于最高名次,如果x+y<=n,那么就可以通过第一次的第1名与第二次的第n名、第一次的第2名与第二次的第n-1名...将剩下的构造成n+1分,使他成为第1名;如果x+y>n,那么将两次比赛的第一名组合一起、第二名组合一起...设组合了t组,使得x-t+y-t<=n-t,就满足了新的x+y<=n,可以算出t=x+y-n,所以他最高就是第x+y-n+1名

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
int n, x, y;
int get_min()
{
    if (x + y <= n)
        return 1;
    return min(n, x + y - n + 1);
}
int get_max()
{
    return min(n, x + y - 1);
}
void solve()
{
    scanf("%d%d%d", &n, &x, &y);
    if (x > y)
        swap(x, y);
    printf("%d %d\n", get_min(), get_max());
}
int main()
{
    int t;
    for (scanf("%d", &t); t >= 1; t--)
        solve();
    return 0;
}

C.Skyscrapers(单调栈/分治+线段树)

题意:要建建筑,要求对于任意一个不能同时存在左、右都有比它高的建筑,同时对于每个i都有给定的mi,每个i不能超过mi。询问这些建筑高度和最大能是多少。

题解:显然满足题意的一定是一个单峰序列,于是可以考虑第i个当最高点的时候,左边的最大总和,而这个是可以递推的,因为当mi>=mi-1的时候第i个可以直接取mi加上去,而当mi<mi-1的时候,要把之前所有大于mi的都变成mi,而之前的部分是单增的,于是可以开个单调栈来维护,复杂度O(n),同理右边的最大总和也可以这么算。还有一种方法:找出区间里的最小值mi,分治,比较左边都取mi+solve右边与左边solve+右边都取mi的大小。用线段树来维护区间。

单调栈:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
typedef long long ll;
ll a[maxn], pre[maxn], nex[maxn], l[maxn], r[maxn];
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    a[0] = a[n + 1] = 0ll;
    stack<int> s;
    s.push(0);
    for (int i = 1; i <= n; i++)
    {
        while (a[s.top()] >= a[i])
            s.pop();
        pre[i] = s.top();
        s.push(i);
        l[i] = l[pre[i]] + a[i] * (i - pre[i]);
    }
    while (!s.empty())
        s.pop();
    s.push(n + 1);
    for (int i = n; i >= 1; i--)
    {
        while (a[s.top()] >= a[i])
            s.pop();
        nex[i] = s.top();
        s.push(i);
        r[i] = r[nex[i]] + a[i] * (nex[i] - i);
    }
    ll mx = 0;
    int id = 0;
    for (int i = 1; i <= n; i++)
        if (mx < l[i] + r[i] - a[i])
            mx = l[i] + r[i] - a[i], id = i;
    for (int i = id - 1; i >= 1; i--)
        a[i] = min(a[i], a[i + 1]);
    for (int i = id + 1; i <= n; i++)
        a[i] = min(a[i], a[i - 1]);
    for (int i = 1; i <= n; i++)
        printf("%lld ", a[i]);
    puts("");
    return 0;
}

分治+线段树

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 7;
int n;
long long a[maxn], b[maxn];
typedef pair<long long, int> SgTreeDataType;
struct treenode
{
    int L, R;
    SgTreeDataType mi, lazy;
} tree[maxn * 4];
inline void push_up(int o)
{
    if (tree[2 * o].mi.first == 0)
        tree[2 * o].mi = {1e9 + 7, 1e9};
    if (tree[2 * o + 1].mi.first == 0)
        tree[2 * o + 1].mi = {1e9 + 7, 1e9};
    if (tree[2 * o].mi.first > tree[2 * o + 1].mi.first)
        tree[o].mi = tree[2 * o + 1].mi;
    else
        tree[o].mi = tree[2 * o].mi;
}

inline void build_tree(int L, int R, int o)
{
    tree[o].L = L, tree[o].R = R;
    if (L == R)
        tree[o].mi = {a[L], L};
    if (R > L)
    {
        int mid = (L + R) >> 1;
        build_tree(L, mid, o * 2);
        build_tree(mid + 1, R, o * 2 + 1);
        push_up(o);
    }
}
inline SgTreeDataType query(int QL, int QR, int o)
{
    int L = tree[o].L, R = tree[o].R;
    if (QL <= L && R <= QR)
        return tree[o].mi;
    else
    {
        int mid = (L + R) >> 1;
        SgTreeDataType mi = {1e9 + 7, 1};
        if (QL <= mid)
        {
            SgTreeDataType res = query(QL, QR, 2 * o);
            if (res.first < mi.first)
                mi = res;
        }
        if (QR > mid)
        {
            SgTreeDataType res = query(QL, QR, 2 * o + 1);
            if (res.first < mi.first)
                mi = res;
        }
        push_up(o);
        return mi;
    }
}

long long solve(int l, int r)
{
    if (l > r)
        return 0L;
    if (l == r)
    {
        b[l] = a[l];
        return 1ll * a[l];
    }
    pair<long long, int> mi = query(l, r, 1);
    long long sum1 = solve(l, mi.second - 1);
    long long sum2 = solve(mi.second + 1, r);
    if (1ll * ((r - mi.second - 1) + 1) * mi.first + mi.first + sum1 >
        1ll * ((mi.second - 1 - l) + 1) * mi.first + mi.first + sum2)
    {
        for (int i = mi.second; i <= r; i++)
            b[i] = mi.first;
        return 1ll * ((r - mi.second - 1) + 1) * mi.first + mi.first + sum1;
    }
    else
    {
        for (int i = l; i <= mi.second; i++)
            b[i] = mi.first;
        return 1ll * ((mi.second - 1 - l) + 1) * mi.first + mi.first + sum2;
    }
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    build_tree(1, n, 1);
    solve(1, n);
    for (int i = 1; i <= n; i++)
        cout << b[i] << " ";
    cout << endl;
}