CSP-J 2023

发布时间 2023-10-22 20:28:10作者: yabnto

[CSP-J 2023] 小苹果

这道题由于不会算时间复杂度,大概用了 \(\frac{3}{10}\) 的时间。

思路

样例我们先手推一下:

1 2 3 4 5 6 7 8
2 3 5 6 8
3 5 8
5 8
8

我们先将每个数的位置对三取模后的数标一下(括号里的数就是位置对三取模后的数):

1(1) 2(2) 3(0) 4(1) 5(2) 6(0) 7(1) 8(2)
2(1) 3(2) 5(0) 6(1) 8(2)
3(1) 5(2) 8(0)
5(1) 8(2)
8(1)

我们观察 \(8\) 的位置对三取模后的数的规律,首先是 \(2\) 然后删掉所有位置是 \(1\) 的数,也就是 \(\left\lceil\dfrac{8}{3}\right\rceil\),所以位置 \(8\) 也就变成了 \(8 - \left\lceil\dfrac{8}{3}\right\rceil = 5\) 位置 \(5\),而原来对三取模的 \(2\) 也就变成了 \(5 \equiv2\pmod{3}\),直到位置对三取模为 \(1\) 为止,它才被删掉,那什么时候结束呢?同样的对于当前个数为 \(n\) 的,它将会被删掉 \(n - \left\lceil\dfrac{n}{3}\right\rceil\) 个数,直到删完,两个问题递归求解即可。然后考试是因为不会算时间复杂度,就一直再算(悲)。

code

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

ll n;

ll S(ll x) {
  if (x == 1) {
    return 1;
  }
  return S(x - ceil(1.0 * x / 3)) + 1;
}

ll C(ll x) {
  if (x % 3 == 1) {
    return 1;
  }
  return C(x - ceil(1.0 * x / 3)) + 1;
}

int main() {
  cin >> n;
  cout << S(n) << " " << C(n) << endl;
  return 0;
}

[CSP-J 2023] 公路

大概又用了 \(\frac{3}{10}\)

思路

由于要算的是最小的油费,而且油箱有时没上限的,所以我们肯定选择在油费最小的站点买完会是最优的,但是第一个点不一定是油费最小的也就是我们还得再最优的位置之前与第一个位置内选一个最优的作为补给,可是这个最优的也不一定是在第一个位置,所以我们还得找一个……,这么做完后,便会发现整个路程分为了几个段,而每个段的第一个位置是当前段里油费最优的,那么我们便可以处理完所有的段,然后分段计费。考试时我先写了一个前缀最小值来分段,可是挂了,所以我又重新写了个双指针的写法才对,此处耗时巨大(悲)。

code

#include <bits/stdc++.h>

using namespace std;

const int MaxN = 1e5 + 10;

long long a[MaxN], c[MaxN], len, n, ans, d;

int main () {
  cin >> n >> len;
  for (int i = 1; i < n; i++) {
    cin >> a[i];
  }
  for (int i = 1; i <= n; i++) {
    cin >> c[i];
  }
  for(int i = 1; i <= n;) {
    int nw = i;
    long long sum = -d;
    for (; i <= n && c[i] >= c[nw]; i++) {
      sum += a[i];
    }
    ans += (sum + len - 1) / len * c[nw];
    d = (sum + len - 1) / len * len - sum;
  }
  cout << ans << endl;
  return 0;
}

[CSP-J 2023] 一元二次方程

最没可能 \(A\) 的一道题,却是最顺畅的一道题,耗时 \(\frac{3}{10}\) 太顺畅了,直接写了 \(101\) 行。

思路

这是到大模拟,我的想法是写一个有理数的结构体,然后自动处理掉有理数规则,然后自动约分和自动将根号最简话,然后直接模拟即可,那这个有理数结构体要处理些什么呢?它分为分子和分母,分子有个普通的计数,和一个根号的计数,然后用一个 \(flag\) 来判断有没有根号,分母就直接记下来就可以了,注意分母不能是负数!。

code

赛时代码

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

struct S {
  ll p1, p2, q;
  bool sqr;

  void I() {
    ll a = 1, b = p2;
    for (ll i = 2; i * i <= p2; i++) {
      if (p2 % i == 0 && ll(sqrt(i)) * ll(sqrt(i)) == i) {
        if (b > p2 / i) {
          b = min(p2 / i, b), a = sqrt(i);
        }
      }
      if (p2 % i == 0 && ll(sqrt(p2 / i)) * ll(sqrt(p2 / i)) == p2 / i) {
        if (b > i) {
          b = min(i, b), a = sqrt(p2 / i);
        }
      }
    }
    p2 = b, p1 *= a;
    ll d = __gcd(p1, q);
    p1 /= d, q /= d;
    if (q < 0) {
      p1 *= -1, q *= -1;
    }
  }

  void print() {
    I();
    if (q != 1) {
      if (!sqr) {
        cout << p1 << "/" << q;
      } else {
        if (p1 != 1) {
          cout << p1 << "*sqrt(" << p2 << ")/" << q;
        } else {
          cout << "sqrt(" << p2 << ")/" << q;
        }
      }
    } else {
      if (!sqr) {
        cout << p1;
      } else {
        if (p1 != 1) {
          cout << p1 << "*sqrt(" << p2 << ")";
        } else {
          cout << "sqrt(" << p2 << ")";
        }
      }
    }
  }
};

ll t, m, a, b, c;

int main () {
  ios::sync_with_stdio(0), cin.tie(0);
  for (cin >> t >> m; t; t--) {
    cin >> a >> b >> c;
    ll dt = b * b - 4 * a * c;
    if (dt < 0) {
      cout << "NO" << '\n';
    } else {
      if (ll(sqrt(dt)) * ll(sqrt(dt)) == dt) {
        S ans1 = {ll(-b + sqrt(dt)), 0, 2 * a, 0}, ans2 = {ll(-b - sqrt(dt)), 0, 2 * a, 0};
        ans1.I(), ans2.I();
        S ans3;
        if (ans1.p1 * ans2.q > ans2.p1 * ans1.q) {
          ans3 = ans1;
        } else {
          ans3 = ans2;
        }
        ans3.print();
      } else {
        S q1 = {-b, 0, 2 * a, 0}, q2 ={(2 * a > 0 ? 1 : -1), dt, 2 * a, 1};
        q1.I(), q2.I();
        if (-b != 0) {
          q1.print();
          cout << "+";
        }
        if (q2.p1 == q2.q) {
          q2.print();
        } else if (q2.p1 % q2.q == 0) {
          q2.print();
        } else if (q2.q % q2.p1 == 0) {
          q2.q = q2.q / q2.p1, q2.p1 = 1;
          q2.print();
        } else {
          q2.print();
        }
      }
      cout << '\n';
    }
  }
  return 0;
}

我如果正常写的代码

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

struct S {
  ll p1, p2, q;
  bool sqr;

  void I() {
    ll a = 1, b = p2;
    for (ll i = 2; i * i <= p2; i++) {
      (p2 % i == 0 && ll(sqrt(i)) * ll(sqrt(i)) == i) && (b > p2 / i) && (b = min(p2 / i, b), a = sqrt(i));
      (p2 % i == 0 && ll(sqrt(p2 / i)) * ll(sqrt(p2 / i)) == p2 / i) && (b > i) && (b = min(i, b), a = sqrt(p2 / i));
    }
    p2 = b, p1 *= a;
    ll d = __gcd(p1, q);
    p1 /= d, q /= d;
    (q < 0) && (p1 *= -1, q *= -1);
  }

  void print() {
    I();
    if (q != 1) {
      if (!sqr) {
        cout << p1 << "/" << q;
      } else {
        (p1 != 1) ? (cout << p1 << "*sqrt(" << p2 << ")/" << q) : (cout << "sqrt(" << p2 << ")/" << q);
      }
    } else {
      if (!sqr) {
        cout << p1;
      } else {
        (p1 != 1) ? (cout << p1 << "*sqrt(" << p2 << ")") : (cout << "sqrt(" << p2 << ")");
      }
    }
  }
};

ll t, m, a, b, c;

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  for (cin >> t >> m; t; t--) {
    cin >> a >> b >> c;
    ll dt = b * b - 4 * a * c;
    if (dt < 0) {
      cout << "NO" << '\n';
    } else {
      if (ll(sqrt(dt)) * ll(sqrt(dt)) == dt) {
        S ans1 = {ll(-b + sqrt(dt)), 0, 2 * a, 0}, ans2 = {ll(-b - sqrt(dt)), 0, 2 * a, 0};
        ans1.I(), ans2.I();
        S ans3 = (ans1.p1 * ans2.q > ans2.p1 * ans1.q ? ans1 : ans2);
        ans3.print();
      } else {
        S q1 = {-b, 0, 2 * a, 0}, q2 = {(2 * a > 0 ? 1 : -1), dt, 2 * a, 1};
        q1.I(), q2.I();
        if (-b != 0) q1.print(), cout << "+";
        (q2.q % q2.p1 == 0) && (q2.q = q2.q / q2.p1, q2.p1 = 1);
        q2.print();
      }
      cout << '\n';
    }
  }
  return 0;
}

好一只压行鸭(

[CSP-J 2023] 旅游巴士

只有 \(\frac{1}{10}\) 了,极限乱搞!

思路

没有思路,暴力乱搞 \(BFS\)

code

算了吧

预估分数 \(300\)