CSP-J 2023 参考代码

校内一位高手做了 CSP-S 的参考代码,于是本人跟风做一个 J 组的。
下列代码目前只在洛谷测试过,并不保证对于 CCF 官方数据的正确性。下列代码已经在 CCF 官方数据下测试通过,正确性可以保证。

P9748 [CSP-J 2023] 小苹果

按照题意模拟很容易找到规律,从而得到一个 O(logn) 的算法。注意两个问题不能同时算出,必须要额外开一个 n 来算第二问。

#include <iostream>

using namespace std;

long long n, res1, res2, tmp;

int main(void) {
	cin >> n;
	tmp = n;
	while (tmp > 3) {
		tmp -= (tmp + 2) / 3;
		res1++;
	}
	cout << res1 + tmp << ' ';
	while (n % 3 != 1) {
		n -= (n + 2) / 3;
		res2++;
	}
	cout << ++res2;
	return 0;
}

P9749 [CSP-J 2023] 公路

“油不够了就要加油”,这是常识中的常识。
或许你可能会想,要是实际开车的时候,能等到油不够了就“回到”油价最少的车站加油,那该多好啊!
思路就在于此,开一个 minn 记录到达过的车站中油价最少值,每次油不够了就直接加上即可。
注意需要前进的公里数可能无法整除每升油可以走的公里数,留心一下由此带来的加减运算。

#include <iostream>

#define int long long

using namespace std;

const int maxn = 1e5 + 10, inf = 1e18;

int n, d;
int v[maxn], a[maxn];
int sumv[maxn], tot, res, price = inf;

inline void gmi(int &x, int y) { x > y ? x = y : 0; }

signed main(void) {
	cin >> n >> d;
	for (int i = 1; i <= n - 1; i++) {
		cin >> v[i];
		sumv[i] = sumv[i - 1] + v[i]; //总共要走的公里数
	}
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	for (int i = 1; i <= n - 1; i++) {
		gmi(price, a[i]);
		if (tot * d < sumv[i]) {
			res += (sumv[i] - tot * d + d - 1) / d * price;
			tot += (sumv[i] - tot * d + d - 1) / d; //买的油总量
		}
	}
	cout << res;
	return 0;
}

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

分类讨论的内容很多,所以直接在注释里面写了。
有一点小技巧:若 a<0 则把 a,b,c 全部变为相反数,从而保持 a 为正数。具体作用请读者自行思考。

#include <iostream>
#include <algorithm>
#include <cmath>

#define int long long
#define double long double

using namespace std;

const double eps = 1e-8;

int T, m;

inline auto sqrtDivide(int x) { //根号化简
	bool flag = true;
	int inte = 1;
	while (flag) {
		flag = false;
		for (int i = 2; i * i <= x; i++) {
			if (x % (i * i) == 0) {
				x /= (i * i);
				inte *= i;
				flag = true;
				break;
			}
		}
	}
	return make_pair(inte, x);
}

inline void integerSolve(int a, int b, int delta) {
	//num -> 分子 deno -> 分母
	int num = -b + (int)sqrt(delta), deno = 2 * a;
	int gcd = __gcd(abs(num), abs(deno));
	//类型 1: 分子为 0
	if (num == 0) cout << 0;
	//类型 2:分母可以被约去
	else if (deno == gcd) cout << num / gcd;
	//类型 3:分母约去后剩下 -1
	else if (-deno == gcd) cout << -num / gcd;
	//类型 4:正常情况。
	else cout << num / gcd << '/' << deno / gcd;
}

inline void floatSolve(int a, int b, int delta) {
	int inte = sqrtDivide(delta).first, delt = sqrtDivide(delta).second;
	int gcd = __gcd(abs(inte), abs(2 * a));
	//q1 != 0,先按照有理数格式输出
	if (b != 0) {
		integerSolve(a, b, 0);
		cout << '+';
	}
	//类型 1: 约分后整数部分和分母均为 1
	if (inte == abs(2 * a)) cout << "sqrt(" << delt << ')' << '\n';
	//类型 2:分子可以被约去
	else if (inte == gcd) cout << "sqrt(" << delt << ")/" << 2 * a / gcd << '\n';
	//类型 3:分母可以被约去
	else if (abs(2 * a) == gcd) cout << inte / gcd << "*sqrt(" << delt << ')' << '\n';
	//类型 4:正常情况。
	else cout << inte / gcd << "*sqrt(" << delt << ")/" << 2 * a / gcd << '\n';
}

signed main(void) {
	cin >> T >> m;
	while (T--) {
		int a, b, c;
		cin >> a >> b >> c;
		if (a < 0) a = -a, b = -b, c = -c; //保证 a 为正数
		int delta = b * b - 4 * a * c;
		if (delta < 0) {
			cout << "NO" << '\n';
			continue;
		} else {
			double sqD = sqrt(delta);
			//sqrt(delta) 的整数与否直接决定是否要输出根号
			if (abs(floor(sqD) - sqD) < eps) integerSolve(a, b, delta), cout << '\n';
			else floatSolve(a, b, delta);
		}
	}
	return 0;
}

P9751 [CSP-J 2023] 旅游巴士

由于每隔 k 秒才会有巴士,所以我们可以根据最短路 modk 的结果拆点建立分层图;
此外到达和离开时间都必须为 k 的整数倍,所以对应修改一下边权,据此对 dijkstra 算法进行微小调整即可使用。
这道题的拆点和分层图和网络流的某些经典模型相似,这就是 J 组的实力吗……

#include <iostream>
#include <cstring>
#include <bitset>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/priority_queue.hpp>
//上面两个 pb_ds 的头文件是为了调用一个“高级一点”的优先队列,其底层为配对堆
//当然直接用普通的二叉堆也能过

#define int long long
#define pii pair<int, int>

using namespace std;
using namespace __gnu_pbds;

const int maxn = 5e4 + 10, maxk = 150;
const int inf = 0x3f3f3f3f3f3f3f3f;

__gnu_pbds::priority_queue<pii, greater<pii>, pairing_heap_tag> Q;
bitset<maxn> vis[maxk]; //比普通的 bool 数组更快的神奇 STL

int n, m, k;
int dis[maxk][maxn];
int head[maxn], nxt[maxn], to[maxn], val[maxn], cnt;

inline void add(int u, int v, int w) {
    nxt[cnt] = head[u], to[cnt] = v, val[cnt] = w, head[u] = cnt++;
}

inline int calc(int x, int k) { //为了处理一点复杂的取整问题
    if (x % k > 0) return x / k + 1;
    return x / k;
}

inline void bfs() {
    memset(dis, 0x3f, sizeof(dis));
    dis[0][1] = 0;
    Q.push({0, 1});
    while (!Q.empty()) {
        int mov = Q.top().first, u = Q.top().second;
        Q.pop();
        if (vis[mov % k][u]) continue;
        vis[mov % k][u] = true;
        for (int i = head[u]; ~i; i = nxt[i]) {
            int v = to[i], dec = mov + 1;
            if (val[i] - mov > 0)
                dec += calc(val[i] - mov, k) * k;
            if (dis[dec % k][v] > dec) {
                dis[dec % k][v] = dec;
                Q.push({dis[dec % k][v], v});
            }
        }
    }
}

signed main() {
    memset(head, -1, sizeof(head));
    cin >> n >> m >> k;
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w);
    }
    bfs();
    if (dis[0][n] >= inf) cout << -1;
    else cout << dis[0][n];
    return 0;
}

本文作者:Coel's Blog

本文链接:https://www.cnblogs.com/Coel-Flannette/p/17793261.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   秋泉こあい  阅读(301)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 アイノマテリアル (feat. 花里みのり&桐谷遥&桃井愛莉&日野森雫&MEIKO) MORE MORE JUMP!
アイノマテリアル (feat. 花里みのり&桐谷遥&桃井愛莉&日野森雫&MEIKO) - MORE MORE JUMP!
00:00 / 00:00
An audio error has occurred.