CSP-J 2023 第二轮认证入门级(含答案)

一。题目 

 

二。答案

T1 ⼩苹果(apple)

每⼀轮拿掉的苹果数量为 。模拟拿苹果的过程,每⼀轮中令 ,当 时最后⼀个苹果会被拿掉。 时间复杂度为对数。 

#include <iostream>
using namespace std;
int n;
int ans1, ans2;
bool flag;
int main() {
    cin >> n;
    while (n) {
        ans1++;
        if (!flag && n % 3 == 1) {
            ans2 = ans1;
            flag = 1;
        }
        n -= n % 3 ? n / 3 + 1 : n / 3;
    }
    cout << ans1 << ' ' << ans2 << '\n';
    return 0;
}

T2 公路(road) 

简单的贪⼼题。 如果下⼀个站点的油费⽐当前站点贵,显然应该在当前站点把油加⾜。 ⽤ 表⽰当前所在的站点, 表⽰当前油箱中的剩余油量,每次找到 之后第⼀个油价低 于 的站点 ,加上⾜够的油开过去即可。注意使⽤ long long 。 双指针遍历即可得出答案,时间复杂度为线性。

#include <iostream>
#define N 100010
#define ll long long
using namespace std;
int n;
ll d, v[N], p[N], ans;
int main() {
    cin >> n >> d;
    for (int i = 1; i < n; i++) cin >> v[i];
    for (int i = 1; i <= n; i++) cin >> p[i];
    int now = 1, nxt = 2;
    ll tank = 0;
    while (now < n) {
        ll dis = v[now];
        while (nxt < n && p[nxt] >= p[now]) 
            dis += v[nxt++];
        int cnt = 0;
        while (tank + cnt * d < dis) cnt++;
        ans += p[now] * cnt;
        tank += cnt * d - dis;
        now = nxt++;
    }
    cout << ans << endl;
    return 0;
}

T3 ⼀元⼆次⽅程(uqe) 

⼤⽔题。 给出⼀元⼆次⽅程 的三个系数 ,求该⽅程⽐较⼤的根,且化简为最简形 式。 ⾸先根据判别式 判定是否⽆解,在有解的情况下,要将 中的完全平⽅因⼦提到根 号外⾯。 设 ,根据算术基本定理 : 如果 为偶数,则将 累乘到 ; 如果 为奇数,则将 累成到 ; 当 时结果为⽆理数, 或 时结果都是有理数,分情况讨论输出即可。 有理数化为最简分式只需分⼦分⺟同除以它们的最⼤公约数。 特别需要注意 的符号,由于题⽬要求输出⽐较⼤的根,所以当 时, 的符号也应该为负。 ⽐较⽅便的处理⽅法是:如果 ,则将 全部反号,避免⽆谓的分类讨论。

#include <cstdio>
#define N 1010
int T, M, a, b, c;
int P[N], C[N], tot;
void divide(int n) {
    tot = 0;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            P[++tot] = i;
            C[tot] = 0;
            while (n % i == 0) {
                n /= i;
                C[tot]++;
            }
        }
    }
    if (n > 1) {
        P[++tot] = n;
        C[tot] = 1;
    }
}
int qpow(int x, int y) {
    int res = 1;
    while (y) {
        if (y & 1) res *= x;
        x *= x;
        y >>= 1;
    }
    return res;
}
int gcd(int x, int y) {
    return y ? gcd(y, x % y) : x;
}
void print_rational(int x, int y) {
    if (x * y < 0) printf("-");
    if (x < 0) x *= -1;
    if (y < 0) y *= -1;
    if (x % y == 0) 
        printf("%d", x / y);
    else 
    printf("%d/%d", x / gcd(x, y), y / gcd(x, y));
}
int main() {
    scanf("%d %d", &T, &M);
    while (T--) {
        scanf("%d %d %d", &a, &b, &c);
        if (a < 0) {
            a *= -1;
            b *= -1;
            c *= -1;
        }
        int delta = b * b - 4 * a * c;
        if (delta < 0) {
        puts("NO");
        continue;
        }
        // 除去 delta 中的完全平⽅因⼦
        divide(delta);
        int d = 1;
        for (int i = 1; i <= tot; i++) {
            if (C[i] & 1) 
                d *= qpow(P[i], (C[i] - 1) >> 1);
            else 
                d *= qpow(P[i], C[i] >> 1);
        }
        delta /= d * d;
        if (delta == 0) 
            print_rational(-b, a << 1);
        else if (delta == 1) {
            print_rational(d - b, a << 1);
        else {
            if (b) {
                print_rational(-b, a << 1);
                printf("+");
            }
            int x = d;
            int y = a << 1;
            if (x % y == 0) {
                x /= y;
                if (x > 1) printf("%d*", x);
                printf("sqrt(%d)", delta);
            } else {
                if (x / gcd(x, y) > 1) printf("%d*", x / gcd(x, y));
                printf("sqrt(%d)/%d", delta, y / gcd(x, y));
            }
        }
        puts("");
        }
    return 0;
}

T4 旅游巴⼠

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 10010
#define M 20010
#define K 110
#define INF 0x3f3f3f3f
int n, m, k;
int dis[N][K];
struct T {
    int head, to, nxt, w;
} a[M];
int tot;
void add(int u, int v, int w) {
    a[++tot].to = v;
    a[tot].w = w;
    a[tot].nxt = a[u].head;
    a[u].head = tot;
}
inline int ceil(int x, int y) {
    return x % y == 0 ? x / y : x / y + 1;
}
void dfs(int u, int now) {
    if (now >= dis[n][0]) return; // 最优性剪枝
    for (int i = a[u].head; i; i = a[i].nxt) {
        int v = a[i].to, w = a[i].w;
        int nxt = now >= w ? now + 1 : now + 1 + ceil(w - now, k) * k;
        if (dis[v][nxt % k] > nxt) {
            dis[v][nxt % k] = nxt;
            dfs(v, nxt);
        }
    }
}
int main() {
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        add(u, v, w);
    }
    memset(dis, 0x3f, sizeof(dis));
    dfs(1, 0);
    printf("%d\n", dis[n][0] == INF ? -1 : dis[n][0]);
    return 0;
}

 如果 ⼀开始进⼊的是错误的分⽀,会导致 数组收敛的很慢。将 的过程改为 AC即可 。

#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#define N 10010
#define M 20010
#define K 110
#define INF 0x3f3f3f3f
int n, m, k;
int dis[N][K];
struct T {
    int head, to, nxt, w;
} a[M];
int tot;
void add(int u, int v, int w) {
    a[++tot].to = v;
    a[tot].w = w;
    a[tot].nxt = a[u].head;
    a[u].head = tot;
}
inline int ceil(int x, int y) {
    return x % y == 0 ? x / y : x / y + 1;
}
struct V {
    int id, dis;
} s, now, nxt;
void bfs() {
    s.id = 1;
    s.dis = dis[1][0] = 0;
    std::queue<V> q;
    q.push(s);
    while (q.size()) {
        now = q.front();
        q.pop();
        int u = now.id;
        for (int i = a[u].head; i; i = a[i].nxt) {
            nxt.id = a[i].to;
            nxt.dis = now.dis >= a[i].w ? now.dis + 1 : now.dis + 1 + ceil(a[i].w - now.dis, k) * k;
            if (dis[nxt.id][nxt.dis % k] > nxt.dis) {
                dis[nxt.id][nxt.dis % k] = nxt.dis;
                q.push(nxt);
            }
        }
    }
}
int main() {
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        add(u, v, w);
    }
    memset(dis, 0x3f, sizeof(dis));
    bfs();
    printf("%d\n", dis[n][0] == INF ? -1 : dis[n][0]);
    return 0;
}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值