P9553 「CROI · R1」浣熊的语言 题解

Part   1:25   pts \texttt{Part 1:25 pts} Part 1:25 pts

25 25 25 分是 m = 0 m=0 m=0 的特殊情况。

m = 0 m=0 m=0,代表每一天都可以按计划学习,那么对于每一个单词直接模拟即可。如果你对数据范围不太敏感,建议数组都开大一点。

时间复杂度 O ( n k ) O(nk) O(nk)

//pre表示当日学习单词数,re表示当日复习单词数
//maxday用来统计最后学习/复习单词的一天
int maxday = 0;
for(int i = 1;i <= n;i++) {
    //对于每一个单词
    pre[d[i]]++;
    maxday = max(maxday,d[i]);
    for(int j = 1;j <= k;j++) {
        int reday = d[i] + t[j];
        re[reday]++;
        maxday = max(maxday,reday);
    }
}

25 25 25 分提交记录

Part   2:65   pts \texttt{Part 2:65 pts} Part 2:65 pts

65 65 65 分是虽然有 m m m,但是可以直接通过暴力模拟。

把特殊的日子用一个 bool 数组存下来,如果哪一天学习单词/复习单词时,有特殊情况,就不断与后面交换,直到哪一天能学习为止。因为我们是将特殊情况在输入时直接处理,所以对后面的程序没有影响。

时间复杂度仍然是 O ( n k ) O(nk) O(nk)

学习单词的特殊处理:

for(int i = 1;i <= m;i++) {
    cin >> s[i];
    spe[s[i]] = true;
}
for(int i = 1;i <= n;i++) {
    if(spe[d[i]] == true) {
        while(spe[d[i]] == true) d[i]++;
    }
}

复习单词的特殊处理:

for(int i = 1;i <= n;i++) {
    pre[d[i]]++;
    maxday = max(maxday,d[i]);
    for(int j = 1;j <= k;j++) {
        int reday = d[i] + t[j];
        if(spe[reday]) {
            while(spe[reday]) reday++;
        }
        re[reday]++;
        maxday = max(maxday,reday);
    }
}

65 65 65 分提交记录

Part   3:100   pts \texttt{Part 3:100 pts} Part 3:100 pts

我们会发现,上一个程序中,最坏的运算次数会达到 1 0 6 × 1 0 3 = 1 0 9 10^6 \times 10^3=10^9 106×103=109 次,所以最后一个 Subtask 有两个点超时了。

(注:赛时的时限是 1.00 1.00 1.00s,把这两个点大力卡卡常,也许还能过;赛后为了卡掉错解,时限放到了 500 500 500ms,就完全不能过了。)

看看数据范围,我们从哪里入手呢?

仔细观察可以发现, d i d_i di t i t_i ti 都是 ≤ 1 0 3 \le 10^3 103 的,也就是说,总天数一定不会超过 2000 2000 2000。那么我们就可以按天记录答案,就可以将 1 0 6 10^6 106 的数量级降低至 2000 2000 2000

由于 d i d_i di 单调不减,所以总时间复杂度为 O ( d n k ) O(d_nk) O(dnk)

//isd[i]表示第i天要学几个词
for(int i = 1;i <= maxd;i++) {
    if(isd[i] && spe[i]) {
        int x = i;
        while(spe[x]) {
            isd[x+1] += isd[x];
            isd[x] -= isd[x];
            x++;
            //这是交换操作
        }
    }
}
for(int i = 1;i <= maxd;i++) {
    if(isd[i] > 0) {
        pre[i] += isd[i];
        for(int j = 1;j <= k;j++) {
            int reday = i + t[j];
            if(spe[reday]) {
                while(spe[reday]) reday++;
            }
            re[reday] += isd[i];
            maxday = max(maxday,reday);
        }
    }
}

运算次数最坏情况下为 1 0 3 × 1 0 3 = 1 0 6 10^3\times10^3=10^6 103×103=106

Part   4 \texttt{Part 4} Part 4

总结:这一题并没有太大的思维难度,比较考察代码实现能力,建议评橙或者黄。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值