ACM模版

描述

题解

这道题属于一道模拟问题吧,如果没有定义错模拟这个词的话。

看到讨论区中有一个 ID 为 zhenhao 的大牛,写了十分详细的题解,我也是看了人家的思路才写的代码,像这种模拟的问题,需要注意的就是思路一定要清晰,把情况考虑周全了,不然很容易错,我就是少考虑一种情况,一直错。繁琐的循环判断有机的组合在一起,最后达到 O(T*(M+N)) 的复杂度还不行,还需要进行剪枝,break 或者不 break 都不影响思路的正确性时一定要记好 break,否则会 TLE,还有需要用输入外挂哦。

这里我就直接借用一下上面所说的大牛的题解,毕竟写得足够详细,我又足够懒惰!

假设现在得到可以凑出[1,t],那么假设有一个数x加进去:
if x<=t+1,那么这个数是可以插入使得可以凑出[1,t+x];
else能够凑出的部分还是[1,t];
所以将集合的元素排序一次,模拟直到找不到上述过程的x即可求出最优值。
然后现在有一个集合B,可以向A添加k个元素,先看A能够得到最优值是t,然后在B中选一个x满足x<= t+1最大,然后增加A的最优值为t+x,继续在A中得到新的最优值t1,然后继续在B中找到一个x满足x<=t1+1最大,增加A的最优值为t1+x,上述过程做k次即可。
想要得到O(n)的复杂度完成上述过程,我的做法是维护一个栈,将找到的满足x<=t+1的x放入栈中知道不满足,那么取出栈顶元素就是最适合放进A的值。所以总的复杂度是O(T*(n+m))。

代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;

const int MAXN = 1010;

int m[MAXN];
int temp[MAXN], key[MAXN], tp;
int s[MAXN][MAXN];
int sk[MAXN], top;  // 栈

template <class T>
inline bool scan_d(T &ret)
{
    char c;
    ret = 0;
    while ((c = getchar()) < '0' || c > '9');
    while (c >= '0' && c <= '9')
    {
        ret = ret * 10 + (c - '0'), c = getchar();
    }
    return true;
}

int exc(int n, int m)
{
    int res = 0;

    for (int i = 0; i < m; i++)
    {
        if (s[n][i] <= res + 1)
        {
            res += s[n][i];
        }
        else
        {
            key[n] = i;
            break;
        }
    }

    return res;
}

int main(int argc, const char * argv[])
{
    // freopen("/Users/zyj/Desktop/input.txt", "r", stdin);

    int n;
    scan_d(n);

    for (int i = 1; i <= n; i++)
    {
        scan_d(m[i]);
        for (int j = 0; j < m[i]; j++)
        {
            scan_d(s[i][j]);
        }
        sort(s[i], s[i] + m[i]);
        temp[i] = exc(i, m[i]);
    }

    int T;
    scan_d(T);

    int a, b, k;
    while (T--)
    {
        scan_d(a);
        scan_d(b);
        scan_d(k);

        top = 0;
        tp = temp[a];
        int j = 0;

        for (int i = key[a]; i < m[a]; i++)
        {
            if (s[a][i] <= tp + 1)
            {
                tp += s[a][i];
            }
            else
            {
                if (!k)
                {
                    break;
                }
                int flag = 1;
                for (; j < m[b]; j++)
                {
                    if (s[b][j] <= tp + 1)
                    {
                        sk[top++] = s[b][j];
                    }
                    else
                    {
                        if (!top)
                        {
                            break;
                        }
                        tp += sk[--top];
                        k--;
                        flag = 0;
                        break;
                    }
                }
                if (flag && k > 0 && top)
                {
                    tp += sk[--top];
                    k--;
                }
                else if (flag)
                {
                    break;
                }
                i--;
            }
        }

        while (k > 0 && top)
        {
            tp += sk[--top];
            k--;
        }

        printf("%d\n", tp);
    }

    return 0;
}