2019 CCF CSP-J2题解

A题:
数字游戏(number)

输入文件名:number.in
输出文件名:number.out
共 20 个测试点,每个测试点 5 分
每个测试点限时 1 秒,运行内存上限 256MB
问题描述
小 K 同学向小 P 同学发送了一个长度为 8 的 01 字符串 来玩数字游戏,小 P 同学想要知道字符串中究竟有多少个 1。

注意:01 字符串为每一个字符是 0 或者 1 的字符串,如“101”(不含双引号)为一个长度为 3 的 01 字符串。

输入格式
输入文件名为 number.in。

输入文件只有一行,一个长度为 8 的 01 字符串 s。

输出格式
输出文件名为 number.out。

输出文件只有一行,包含一个整数,即 01 字符串中字符 1 的个数。

样例 1 输入

00010100
样例 1 输出

2
样例 1 解释
该 01 字符串中有 2 个字符 1。

样例 2 输入

11111111
样例 2 输出

8
样例 2 解释
该 01 字符串中有 8 个字符 1。

样例 3 输入

01010101
样例 3 输出

4
数据范围
对于 20% 的数据,保证输入的字符全部为 0。

对于 100% 的数据,输入只可能包含字符 0 和字符 1,字符串长度固定为 8。

题解说明:简单题,不解释。

100分C++代码:

#include 

using namespace std;

int main(void)
{
    freopen("number.in", "r", stdin);
    freopen("number.out", "w", stdout);

    string s;

    cin >> s;

    int ans = 0;
    for(int i = 0; s[i]; i++)
        if(s[i] == '1') ans++;

    cout << ans << endl;

    fclose(stdin);
    fclose(stdout);

    return 0;
}

B题:
公交换乘(transfer)

输入文件名:transfer.in
输出文件名:transfer.out
共 20 个测试点,每个测试点 5 分
每个测试点限时 1 秒,运行内存上限 256MB
题目描述
著名旅游城市 B 市为了鼓励大家采用公共交通方式出行,推出了一种地铁换乘公交车的优惠方案:
在搭乘一次地铁后可以获得一张优惠票,有效期为 45 分钟,在有效期内可以消耗这张优惠票,免费搭乘一次票价不超过地铁票价的公交车。在有效期内指开始乘公交车的时间与开始乘地铁的时间之差小于等于 45 分钟,即
tbus − tsubway ≤ 45
搭乘地铁获得的优惠票可以累积,即可以连续搭乘若干次地铁后再连续使用优惠票搭乘公交车。
搭乘公交车时,如果可以使用优惠票一定会使用优惠票;如果有多张优惠票满足条件,则优先消耗获得最早的优惠票。
现在你得到了小轩最近的公共交通出行记录,你能帮他算算他的花费吗?
输入格式
输入文件名为 transfer.in。
输入文件的第一行包含一个正整数 nn,代表乘车记录的数量。
接下来的 n 行,每行包含 3 个整数,相邻两数之间以一个空格分隔。第 i 行的第 1 个整数代表第 i 条记录乘坐的交通工具,0 代表地铁,1 代表公交车;第 2 个整数代表第 i 条记录乘车的票价 pricei;第三个整数代表第 i 条记录开始乘车的时间 ti (距 0 时刻的分钟数)。
我们保证出行记录是按照开始乘车的时间顺序给出的,且不会有两次乘车记录出现在同一分钟。
输出格式
输出文件名为 transfer.out。
输出文件有一行,包含一个正整数,代表小轩出行的总花费。
样例 1 输入

6
0 10 3
1 5 46
0 12 50
1 3 96
0 5 110
1 6 135
样例 1 输出

36
样例 1 解释
第一条记录,在第 3 分钟花费 10 元乘坐地铁。
第二条记录,在第 46 分钟乘坐公交车,可以使用第一条记录中乘坐地铁获得的优惠票,因此没有花费。
第三条记录,在第 50 分种花费 12 元乘坐地铁。
第四条记录,在第 96 分钟乘坐公交车,由于距离第三条记录中乘坐地铁已超过 45 分钟,所以优惠票已失效,花费 3 元乘坐公交车。
第五条记录,在第 110 分钟花费 5 元乘坐地铁。
第六条记录,在第 135 分钟乘坐公交车,由于此时手中只有第五条记录中乘坐地铁获得的优惠票有效,而本次公交车的票价为 6 元,高于第五条记录中地铁的票价 5 元, 所以不能使用优惠票,花费 6 元乘坐公交车。
总共花费 36 元。
样例 2 输入

6
0 5 1
0 20 16
0 7 23
1 18 31
1 4 38
1 7 68
样例 2 输出

32
样例 2 解释
第一条记录,在第 1 分钟花费 5 元乘坐地铁。
第二条记录,在第 16 分钟花费 20 元乘坐地铁。
第三条记录,在第 23 分钟花费 7 元乘坐地铁。
第四条记录,在第 31 分钟乘坐公交车,此时只有第二条记录中乘坐的地铁票价高于本次公交车票价,所以使用第二条记录中乘坐地铁获得的优惠票。
第五条记录,在第 38 分钟乘坐公交车,此时第一条和第三条记录中乘坐地铁获得的优惠票都可以使用,使用获得最早的优惠票,即第一条记录中乘坐地铁获得的优惠票。
第六条记录,在第 68 分钟乘坐公交车,使用第三条记录中乘坐地铁获得的优惠票。
总共花费 32 元。
数据范围
对于 30% 的数据,n≤1000,ti ≤10^6 。
另有 15% 的数据,ti ≤10^7,pricei都相等。
另有 115% 的数据,ti ≤10^9,price_ipricei都相等。
对于 100% 的数据,n≤105 ,ti ≤109 ,pricei ≤1000。

解题说明:用链表来实现,不解释。

100分C++代码:

#include 

using namespace std;

struct Bonus {
    int price;
    int time;
    Bonus() : price(0), time(0) {}
    Bonus(int p, int t) : price(p), time(t) {}
};

int main() {
    freopen("transfer.in", "r", stdin);
    freopen("transfer.out", "w", stdout);

    int n;
    unsigned long long ans = 0;
    list<Bonus> bonus;

    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        int type, price, time;
        scanf("%d %d %d", &type, &price, &time);

        if (type == 0) {
            ans += price;
            bonus.push_back(Bonus(price, time));
        } else if (type == 1) {
            list<Bonus>::iterator iter;
            bool flag = false;
            for (iter = bonus.begin(); iter != bonus.end();) {
                if (time - iter->time <= 45) {
                    if (price <= iter->price) {
                        bonus.erase(iter++);
                        flag = true;
                        break;
                    } else
                            iter++;
                } else
                    bonus.erase(iter++);
            }

            if (!flag)
                ans += price;
        }
    }

    printf("%llu\n", ans);

    fclose(stdin);
    fclose(stdout);

    return 0;
}

C题:
纪念品(souvenir)

输入文件名:souvenir.in
输出文件名:souvenir.out
共 20 个测试点,每个测试点 5 分
每个测试点限时 1 秒,运行内存上限 256MB
问题描述
小伟突然获得一种超能力,他知道未来 T 天 N 种纪念品每天的价格。某个纪念品的价格是指购买一个该纪念品所需的金币数量,以及卖出一个该纪念品换回的金币数量。
每天,小伟可以进行以下两种交易 无限次:
任选一个纪念品,若手上有足够金币,以当日价格购买该纪念品;
卖出持有的任意一个纪念品,以当日价格换回金币。
每天卖出纪念品换回的金币可以立即用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币。当然,一直持有纪念品也是可以的。
T 天之后,小伟的超能力消失。因此他一定会在第 T 天卖出所有纪念品换回金币。
小伟现在有 M 枚金币,他想要在超能力消失后拥有尽可能多的金币。
输入格式
输入文件名为 souvenir.in。
第一行包含三个正整数 T,N,M,相邻两数之间以一个空格分开,分别代表未来天数 T,纪念品数量 N,小伟现在拥有的金币数量 M。
接下来 T 行,每行包含 N 个正整数,相邻两数之间以一个空格分隔。第 i 行的 N 个正整数分别为Pi,1, Pi,2, …… , Pi,N,其中 Pi,j表示第 i 天第 j 种纪念品的价格。
输出格式
输出文件名为 souvenir.out。
输出仅一行,包含一个正整数,表示小伟在超能力消失后最多能拥有的金币数量。
输入样例 1

6 1 100
50
20
25
20
25
50
输出样例 1

305
输入输出样例 1 说明
最佳策略是:
第二天花光所有 100 枚金币买入 5 个纪念品 1;
第三天卖出 5 个纪念品 1,获得金币 125 枚;
第四天买入 6 个纪念品 1,剩余 5 枚金币;
第六天必须卖出所有纪念品换回 300 枚金币,第四天剩余 5 枚金币,共 305 枚金币。
超能力消失后,小伟最多拥有 305 枚金币。
输入样例 2

3 3 100
10 20 15
15 17 13
15 25 16
输出样例 2

217
输入输出样例 2 说明
最佳策略是:
第一天花光所有金币买入 10 个纪念品 1;
第二天卖出全部纪念品 1 得到 150 枚金币并买入 8 个纪念品 2 和 1 个纪念品 3,剩余 1 枚金币;
第三天必须卖出所有纪念品换回 216 枚金币,第二天剩余 1 枚金币,共 217 枚金币。
超能力消失后,小伟最多拥有 217 枚金币。
数据规模与约定
对于 10% 的数据,T=1。
对于 30% 的数据,T≤4,N≤4,M≤100,所有价格 10≤Pi,j≤100。
对于 15% 的数据,T≤100,N=1。
对于 15% 的数据,T=2,N≤100。
对于 100% 的数据,T≤100,N≤100,M≤103,所有价格 1≤Pi,j≤104 ,数据保证任意时刻,小明手上的金币数不可能超过 10^4 。

解题说明:这是一个完全背包问题,动态规划来解,不解释。

100分C++代码:

#include

#define MAX(a, b) (((a) > (b)) ? (a) : (b))

using namespace std;

const int T = 100;
const int N = 100;
const int P = 10000;
int t, n, m, a[T + 1][N + 1], dp[P + 1];

int main()
{
    freopen("souvenir.in", "r", stdin);
    freopen("souvenir.out", "w", stdout);

    scanf("%d%d%d", &t, &n, &m);
    for(int i = 1; i <= t; i++)
        for(int j = 1; j <= n; j++) scanf("%d", &a[i][j]);

    for(int i = 1; i < t; i++) {
        memset(dp, 0, sizeof(dp));
        for(int j = 1; j <= n; j++)
            for(int k = a[i][j]; k <= m; k++)
                dp[k] = MAX(dp[k], dp[k-a[i][j]] + a[i+1][j] - a[i][j]);
        m = dp[m] + m;
    }

    printf("%d\n", m);

    fclose(stdin);
    fclose(stdout);

    return 0;
}

你可能感兴趣的:(#,CCF-CSPJS)