跳转至

题解

OJ 1-10 题解

T1

提供两个解法,分别是用队列模拟和用数组模拟(记录入队时间和状态):

// queue队列模拟
#include <bits/stdc++.h>
#define N 15
#define M 1005
#define ll long long
using namespace std;
int n, m;
int T[N], W[N];
int t[M], w[M];
struct tmp
{
    int i;
    int enterTime;
};
queue <tmp> trans[N]; // 传送带队列
queue <tmp> wait[N]; // 等待区队列
ll sum[N];
int main()
{
    scanf("%d %d", &n, &m);
    int minW = 0;
    for (int i = 1; i <= n; i++) {
        scanf("%d %d", &T[i], &W[i]);
        if (!minW || minW > W[i]) minW = W[i];
    }
    int flag = 1;
    for (int i = 1; i <= m; i++) {
        scanf("%d %d", &t[i], &w[i]);
        if (w[i] > minW) flag = 0;
    }
    if (!flag) {
        printf("invalid\n");
        return 0;
    }
    int Time = 0;
    int l = 1;
    int finished = 0;
    while (++Time) {
        for (int i = 2 * n; i; i--) { // 从后往前更新,更新顺序为传送带->等待区->传送带->等待区->...
            if ((i & 1) == 0) { // trans 传送带处理
                int id = i / 2;
                while (!trans[id].empty() && Time - trans[id].front().enterTime >= T[id]) {
                    tmp now = trans[id].front();
                    trans[id].pop();
                    sum[id] -= w[now.i];
                    if (id < n) {
                        if (sum[id + 1] + w[now.i] <= (ll)W[id + 1] && wait[id + 1].empty()) { 
                            // 等待区为空才能直接进入下一个传送带,否则需要等之前进入传送带的物品
                            trans[id + 1].push({now.i, Time});
                            sum[id + 1] += w[now.i];
                        }
                        else {
                            wait[id + 1].push({now.i, Time});
                        }
                    }
                    else finished++;
                }
            }
            else { // wait 等待队列处理
                int id = i / 2 + 1;
                while (!wait[id].empty() && sum[id] + w[wait[id].front().i] <= (ll)W[id]) {
                    tmp now = wait[id].front();
                    wait[id].pop();
                    trans[id].push({now.i, Time});
                    sum[id] += w[now.i];
                }
            }
        }
        while (l <= m && t[l] <= Time) { // 新物品进入整个系统
            if (w[l] + sum[1] <= W[1] && wait[1].empty()) {
                trans[1].push({l, Time});
                sum[1] += w[l];
            }
            else {
                wait[1].push({l, Time});
            }
            l++;
        }
        if (finished == m) break;
    }
    printf("%d\n", Time);
    return 0;
}
// 数组模拟
#include<cstdio>
long long w[1010], mxw[15], miw = 10000000000ll, weightOnBelt[15];
int n, m;
int head[15], tail[15], leavetime[1010], passtime[15], ans;
int main()
{
    scanf("%d%d", &n, &m);
    head[0] = m;
    tail[0] = 1;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%lld", &passtime[i], &mxw[i]);
        tail[i] = 1;
        miw = miw < mxw[i] ? miw : mxw[i];
    }
    for(int i = 1; i <= m; i++)
    {
        scanf("%d%lld", &leavetime[i], &w[i]);
        if(w[i] > miw)
        {
            printf("invalid\n");
            return 0;
        }
    }
    while(tail[n] < m+1)
    {
        int dt = 2100000; // 设定一个足够大的值
        for(int i = 0; i <= n; i++)
        {
            if(tail[i] <= head[i])
                dt = dt < leavetime[tail[i]] ? dt : leavetime[tail[i]];
        }
        ans += dt;
        for(int i = 1; i <= m; i++)
            leavetime[i] -= dt;
        for(int i = 0; i <= n; i++)
        {
            while(leavetime[tail[i]] == 0 && tail[i] <= head[i])
            {
                weightOnBelt[i] -= w[tail[i]];
                tail[i]++;
            }
        }
        for(int i = 1; i <= n; i++)
        {
            while(head[i] < m && leavetime[head[i]+1] <= 0 && weightOnBelt[i] + w[head[i]+1] <= mxw[i])
            {
                head[i]++;
                weightOnBelt[i] += w[head[i]];
                leavetime[head[i]] = passtime[i];
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

可以看出,数组模拟的代码明显要简单不少。用数组模拟简单数据结构(栈、队列、链表等)是较简便的方法。

T2

#include <cstdio>
#include <stack>

#define _N 100010

int n;

std::stack<int> s1, s2;

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int opt, x;
        scanf("%d", &opt);
        switch(opt) {
        case 1:
            if (s1.empty()) {
                puts("invalid option 1");
            } else {
                s2.push(s1.top());
                s1.pop();
            }
            break;
        case 2:
            if (s2.empty()) {
                puts("invalid option 2");
            } else {
                s1.push(s2.top());
                s2.pop();
            }
            break;
        case 3:
            scanf("%d", &x);
            s1.push(x);
            break;
        case 4:
            if (s1.empty()) {
                puts("invalid option 4");
            } else {
                s1.pop();
            }
            break;
        case 5:
            if (s1.empty()) {
                puts("invalid option 5");
            } else {
                printf("%d\n", s1.top());
            }
            break;
        case 6:
            printf("%d\n", (int)s1.size());
            break;
        }
    }
    return 0;
}

双栈模拟即可。

T3

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 107, INF = 0x3f3f3f3f;
char s[107], t[107];
ll len[107];
int n, m;
char solve(int day, ll k){
    if(day == 1) return s[k];
    if(day == 2) return t[k];
    assert(k <= len[day]);
    if(k <= len[day - 2])return solve(day - 2, k);
    else return solve(day - 1, k - len[day - 2]);
}
int main(){
    scanf("%s", s + 1); // 表示从s字符数组下标1的位置开始读入
    scanf("%s", t + 1);
    n = strlen(s + 1);
    m = strlen(t + 1);
    len[1] = n, len[2] = m;
    for(int i = 3; i <= 35; i++) 
        len[i] = len[i - 1] + len[i - 2];
    int Q;
    scanf("%d", &Q);
    while(Q--) {
        int day; ll k;
        scanf("%d%lld", &day, &k);
        for(ll i = k; i <= min(k + 9, len[day]); i++) 
            printf("%c", solve(day, i));
        putchar('\n');
    }
    return 0;
}

题目中已经推荐本题对于10个连续的字母,当作10个分开的字母各自计算并输出。考虑如果将10个字母递归地放入计算函数中一并输出(即将递归的solve增加一个参数表示“想要输出的长度”),那么想要计算的段很有可能在某时某刻“跨越”了组成当前段的两个子段,那么就需要对于两个分别的solve函数截取不同的“字母长度”参数,计算起来容易出错。