CSP-J 2023 赛前模拟赛 Day 4 比赛复盘
CSP-J 2023 赛前模拟赛 Day 4 比赛复盘
分数:$20+80+40+10=150$
分析:
T1:
第一题是一道数学题。主要思路是对于不确定的比赛场次,最少举办了 $\left\lceil\dfrac{k}{2}\right\rceil$ 场,其中 $k$ 表示不确定的比赛场次的个数;最多举办了 $k$ 场。
AC Code:
#include <cstdio>
#include <cstring>
using namespace std;
bool b[4004];
int n, k;
int main()
{
    memset(b, true, sizeof(b));
    scanf("%d%d", &n, &k);
    b[0] = false;
    while(k--)
    {
        int t, x;
        scanf("%d%d", &t, &x);
        b[x] = false;
        if(t == 1)
        {
            int y;
            scanf("%d", &y);
            b[y] = false;
        }
    }
    int l = 0, r = 0;
    for(int i = 1; i < n; i++)
        if(b[i])
        {
            if(b[i - 1])
            {
                b[i] = false;
                l--;
            }
            l++;
            r++;
        }
    printf("%d %d", l, r);
}T2
第二题是一道前缀和的应用题。这里需要对操作数和操作结果两项进行前缀和优化。这道题我想到了,但是实现的时候错了,导致时间复杂度升为 $O(n+m+k+mk)$,TLE $20\text{pts}$。
AC Code:
#include <cstdio>
using namespace std;
using LL = long long;
const int N = 100003;
struct Op
{
    int l, r, d;
    LL s;
} c[N];
LL a[N], s[N];
int main()
{
    int n, m, k;
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= n; ++i)
        scanf("%lld", &a[i]);
    for(int i = 1; i <= m; ++i)
        scanf("%d%d%d", &c[i].l, &c[i].r, &c[i].d);
    while(k--)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        ++c[x].s;
        --c[y + 1].s;
    }
    for(int i = 1; i <= m; ++i)
    {
        c[i].s += c[i - 1].s;
        s[c[i].l] += c[i].d * c[i].s;
        s[c[i].r + 1] -= c[i].d * c[i].s;
    }
    for(int i = 1; i <= n; ++i)
    {
        s[i] += s[i - 1];
        printf("%lld ", a[i] + s[i]);
    }
    return 0;
}T3
第三题是一道浮点数二分的题。二分条件为是否有足够多的数可以达到当前电量。另有 $40\text{pts}$ 可以直接通过求平均值输出获得。
AC Code:
#include <cstdio>
using namespace std;
int a[10003], n, k;
inline bool check(const double &x)
{
    double u = 0, v = 0;
    for(int i = 1; i <= n; ++i)
        if(a[i] >= x)
            v += a[i] - x;
        else
            u += x - a[i];
    v = v * (100 - k) / 100;
    return u <= v;
}
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    double L = 0, R = 1000;
    for(int _ = 0; _ < 500; ++_)
    {
        double M = (L + R) / 2; //double 不允许使用位运算,烦!
        if(check(M))
            L = M;
        else
            R = M;
    }
    printf("%.8lf", L);
    return 0;
}T4
第四题是一道贪心题。贪心思路是在保证抗寒轮胎可以使用 $k$ 天的情况下尽量少换胎。具体操作是将气温高于 $0$ 摄氏度日期按升序排序,然后贪心地选择这些日期使用抗寒轮胎。
AC Code:
#include <cstdio>
#include <climits>
#include <set>
using namespace std;
set<pair<int, int>> s;
int a[200003], k, ans = INT_MAX;
void solve(int cnt, int res)
{
    for(const auto &p: s)
    {
        cnt += p.first;
        if(cnt > k)
            break;
        res -= 2;
    }
    ans = min(ans, res);
}
int main()
{
    int n, cnt = 0, t = 0, res = 0;
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d", &a[i]);
        if(a[i] < 0)
            ++cnt;
    }
    if(cnt > k)
    {
        printf("-1");
        return 0;
    }
    for(int i = 1; i <= n; ++i)
        if(a[i] < 0)
        {
            if(t > -1)
            {
                ++res;
                if(t > 0)
                    s.insert({t, i - 1});
                t = -1;
            }
        }
        else
            if(t > -1)
            {
                if(t > 0)
                    ++t;
            }
            else
            {
                t = 1;
                ++res;
            }
    if(t > 0 && cnt + t <= k)
        solve(cnt + t, res - 1);
    solve(cnt, res);
    printf("%d", ans);
    return 0;
}总结:
这次模拟赛整体还算可以。第一题出现重大失误,只获得了 $20\text{pts}$;第二题出现小失误,但是分数可观,只丢了 $20\text{pts}$;第三题和第四题在预测之内,可以接受,但是第三题本身有能力做到 $100\text{pts}$,仍需努力!
签名(你们觉得哪个更好看一些,评论区发表一下):
$\texttt{TigerTan}$
$\text{TigerTan}$
$TigerTan$
日期:
$2023.10.05$

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号