26杭电暑期第八场(后半)快读|快写|tarjan|路径DP|mex转化|扫描线|前缀和|二分图

1007

快速IO tarjan缩点

IO

首先这题卡IO,非常罕见,可能这就是OI出题人的毛病吧。。。

使用scanf和关流cin都会超时,使用getchar()的普通快读,也很极限。出题人的预期做法是fread,fwrite的快读快写,这里贡献一个基于freadfwriteFastIO类的模板。

一般的io慢,是因为都是基于getchar()的,每次只读取一个字符,但却要调用一次read系统调用。在io优化中一个重要的思想是,内存里的数据解析是很快的,瓶颈在于把数据从stdinfile读取到内存的过程中系统调用的开销,应该尽量减少系统调用的次数。

fread之所以快,就是优化了这一点,他的参数接受一个数组指针,用这个数组作为缓冲区,然后依次读取指定大小的数据块到缓冲区,然后接下来的数据解析都直接在这块缓冲区上进行。

fread(in_buf, 1, BUF_SIZE, stdin),这里的四个参数依次是,

  • 缓冲区数组指针,
  • 单个数据大小,也就是每一步赋值多大的数据,这里设为一个字节,也就是认为读取的是char类型,
  • 读取的数据块大小
  • 输入流类型,可以是stdin,也可以是file

这里我们可以设置很大的缓冲区,比如1MB,这样每读1MB的数据,才需要进行一次read系统调用,大大加速读入。

对于输出,也是类似的,设置一个输出缓冲区,写满了才调用一次fwrite,进行一次到stdout的输出。

题目思路

回到这题本身,输入一个网格图,有一些障碍物,还有一些单向传送门,可以从一个点传到另一个点。q次询问,每次问一个点能否移动到另一个点?

首先不考虑传送门,网格图上每个联通块内都可以相互到达,可以做一个dfs染色找到所有联通块,然后把每个联通块抽象成一个点。

对于传送门,在抽象出来的这个新图上相当于加了一些有向边,查询连通性,考虑用tarjan求强联通分量即可,在一个scc的相互可达,把一个scc的点缩点,成为一个点。

这样又建了一个新图,这个新图一定是个DAG了。这个新图上查询连通性,可以从每个点出发,做bfs找到所有可达点,也可以用Bitset表示每个点的状态,把DAG的边全部取反,做一个DP,每个点的bitset记录,从这个点出发可以到达的点集。

bitset是一般解法。但注意到这题保证传送门个数k=100,也就是虽然点数n=5e4,但是有向边只有100条,那么这个图大部分点都是孤立点,我们显然只用对有边的点为起点做bfs,并且这些边组成的子图,规模也只有O(k)O(k)O(k),这样复杂度只有O(k2)O(k^2)O(k2),并不会O(n2)O(n^2)O(n2),第一种bfs做法也完全可以接受。

c 复制代码
struct FastIO {
	static const int BUF_SIZE = 1 << 20; // 1MB 输入/输出缓冲区
	char in_buf[BUF_SIZE], out_buf[BUF_SIZE];
	int in_pos, in_len, out_pos;

	// 构造函数:初始化指针
	FastIO() : in_pos(0), in_len(0), out_pos(0) {}

	// 析构函数:程序结束或对象销毁时,自动将残余数据刷新到 stdout
	~FastIO() {
		flush();
	}

	// 手动刷新输出缓冲区
	inline void flush() {
		if (out_pos > 0) {
			fwrite(out_buf, 1, out_pos, stdout);
			out_pos = 0;
		}
	}

	// --- 输入逻辑 ---
	inline char get_char() {
		if (in_pos == in_len) {
			in_pos = 0;
			in_len = fread(in_buf, 1, BUF_SIZE, stdin);
			if (in_len == 0) return EOF;
		}
		return in_buf[in_pos++];
	}

	// 读入整数 (支持 int, long long, __int128 等)
	template <typename T>
	inline bool read(T &x) {
		x = 0;
		int f = 1;
		char ch = get_char();
		if (ch == EOF) return false;
		while (!isdigit(ch)) {
			if (ch == '-') f = -1;
			ch = get_char();
			if (ch == EOF) return false;
		}
		while (isdigit(ch)) {
			x = x * 10 + (ch ^ 48);
			ch = get_char();
		}
		x *= f;
		return true;
	}

	// 读入非空白字符
	inline bool read(char &c) {
		c = get_char();
		while (c != EOF && c <= 32) c = get_char();
		return c != EOF;
	}

	// 读入单词/字符串
	inline bool read(std::string &s) {
		s.clear();
		char c = get_char();
		while (c != EOF && c <= 32) c = get_char();
		if (c == EOF) return false;
		while (c != EOF && c > 32) {
			s.push_back(c);
			c = get_char();
		}
		return true;
	}

	// --- 输出逻辑 ---
	inline void write_char(char c) {
		if (out_pos == BUF_SIZE) flush();
		out_buf[out_pos++] = c;
	}
	
	inline void write(char c) { write_char(c); }

	// 输出整数
	template <typename T>
	inline void write(T x) {
		if (x < 0) {
			write_char('-');
			x = -x;
		}
		if (x == 0) {
			write_char('0');
			return;
		}
		char stk[24];
		int top = 0;
		while (x) {
			stk[top++] = (x % 10) ^ 48;
			x /= 10;
		}
		while (top) write_char(stk[--top]);
	}

	// 输出字符串
	inline void write(const char *s) {
		while (*s) write_char(*s++);
	}

	inline void write(const std::string &s) {
		for (char c : s) write_char(c);
	}
} io; // 定义全局对象 io

void solve() {
	int n, m, k, q;
	io.read(n);
	io.read(m);
	io.read(k);
	io.read(q);
	vvi a(n + 1, vi(m + 1));
	rep(i, 1, n) {
		rep(j, 1, m) {
			char c;
			io.read(c);
			if (c == '.') {
				a[i][j] = 1;
			}
		}
	}


	vvi vis(n + 1, vi(m + 1));
	int c0 = 0;

	auto &&dfs = [&](auto &&dfs, int x, int y, int c)->void{
		vis[x][y] = c;
		rep(i, 0, 3) {
			int nx = x + dx[i];
			int ny = y + dy[i];
			if (nx < 1 || nx > n || ny < 1 || ny > m)continue;
			if (a[nx][ny] == 0 || vis[nx][ny] > 0)continue;
			dfs(dfs, nx, ny, c);
		}
	};
	rep(i, 1, n) {
		rep(j, 1, m) {
			if (!vis[i][j] && a[i][j]) {
				dfs(dfs, i, j, ++c0);
			}
		}
	}


	vvi g(c0 + 1);
	rep(i, 1, k) {
		int x1, y1, x2, y2;
		io.read(x1), io.read(y1), io.read(x2), io.read(y2);
		int c1 = vis[x1][y1], c2 = vis[x2][y2];
		if (c1 != c2)g[c1].push_back(c2);
	}

	vector<pii>Q(q + 1);
	rep(i, 1, q) {
		int x1, y1, x2, y2;
		io.read(x1), io.read(y1), io.read(x2), io.read(y2);
		Q[i] = {vis[x1][y1], vis[x2][y2]};
	}

	int cnt = 0, tot = 0, top = 0;
	vi co(c0 + 10), dfn(c0 + 10), in(c0 + 10), low(c0 + 10), s(c0 + 10), ind(c0 + 10);

	auto &&tarjan = [&](auto &&tarjan, int x)->void {
		dfn[x] = low[x] = ++cnt;
		s[++top] = x;
		ind[x] = 1;
		for (int v : g[x]) {
			if (!dfn[v]) {
				tarjan(tarjan, v);
				low[x] = min(low[x], low[v]);
			} else if (ind[v]) {
				low[x] = min(low[x], low[v]);
			}
		}
		if (low[x] == dfn[x]) {
			++tot;
			while (1) {
				int X = s[top--];
				co[X] = tot;
				ind[X] = 0;
				if (!(x ^ X)) {
					break;
				}
			}
		}
	};

	rep(i, 1, c0) {
		if (!dfn[i]) {
			tarjan(tarjan, i);
		}
	}

	vvi g1(tot + 10);
	rep(u, 1, c0) {
		for (int v : g[u]) {
			if (co[v] != co[u]) {
				g1[co[u]].push_back(co[v]);
			}
		}
	}

	vi ans(q + 1);
	vector<vector<pii>> bin(tot + 10);
	rep(i, 1, q) {
		int u = Q[i].first, v = Q[i].second;
		if (co[u] == co[v]) {
			ans[i] = 1;
		} else {
			bin[co[u]].emplace_back(co[v], i);
		}
	}

	vi d(tot + 10), time(tot + 10);
	int TIME = 0;
	rep(i, 1, tot) {
		TIME++;
		if (g1[i].size() != 0) {
			queue<int>q;
			q.push(i);
			if (time[i] != TIME) {
				time[i] = TIME;
				d[i] = 0;
			}
			d[i] = 1;

			while (q.size()) {
				int u = q.front();
				q.pop();
				for (int v : g1[u]) {
					if (time[v] != TIME) {
						d[v] = 0;
						time[v] = TIME;
					}
					if (!d[v]) {
						d[v] = 1;
						q.push(v);
					}
				}
			}

			for (auto [v, id] : bin[i]) {
				if (time[v] != TIME) {
					time[v] = TIME;
					d[v] = 0;
				}
				if (d[v]) {
					ans[id] = 1;
				}
			}
		}
	}

	rep(i, 1, q) {
		io.write(ans[i]);
		io.write('\n');
	}

//	cout << '\n';


}

1008

路径DP mex转化

一个树,可以给n个点,分别赋值为一个0,n−10,n-10,n−1的排列。问整棵树所有点对之间的路径,mex之和的最大值和最小值?

最小值

先看最小值,是可以很容易做到很小的具体来说,只要让0位于一个叶子上,那么除了以这个叶子为一个端点的n条路径外,其他路径都不含0,mex都是0了

对于以这个0叶子为一个端点的全部路径,mex至少为1,那么类似的,我们想让mex=1的路径个数最大化,更大的mex尽量少,那么可以把1安排在另一个叶子上,这样只有以01为两个端点的这一条路径,mex大于1,其余以0为端点的路径mex=1。

接下来考虑2的位置,如果这棵树不是一条链,那么可以把2放在01这条路径之外的点上,这样01这条路径mex就是2了。这样整体答案是1×(n−1)+2=n+11\times (n-1)+2=n+11×(n−1)+2=n+1

如果这棵树是一条链,那么01这两个叶子就是链的两个端点了,01路径上包含0,n−10,n-10,n−1全部点,01路径mex等于n,其余路径,前面的分析仍然是成立的,有n−1n-1n−1条mex=1的,其余mex都为0。整体答案为1×(n−1)+n=2n−11\times(n-1)+n=2n-11×(n−1)+n=2n−1

最大值

最大值要复杂一些,没有这种O(1)O(1)O(1)的策略了。

考虑转化一下mex公式,设si=(0,1...i)s_i=(0,1...i)si=(0,1...i),一个路径的mex,等于它包含的sis_isi的个数,比如路径点集为(0,1,2)(0,1,2)(0,1,2),包含s0,s1,s2s_0,s_1,s_2s0,s1,s2,3个前缀集合,则路径mex等于3

那么所有路径p的mex之和,就等于

∑p∑i=0n−1p包含si \sum_p\sum_{i=0}^{n-1}p包含s_i p∑i=0∑n−1p包含si

其中中括号,里面的语句为真则取值1,否则取值0

可以交换求和顺序

∑i=0n−1∑pp包含si \sum_{i=0}^{n-1}\sum_pp包含s_i i=0∑n−1p∑p包含si

也就是对于每个前缀集合sis_isi,求有多少路径包含它。现在树上点权是我们决定的,那么就是要找到一个策略,让包含sis_isi的路径数尽量多。

显然这样的策略就是让所有sis_isi都尽可能排布在一条链上,设当前uv链长度k,包含了0,k−10,k-10,k−1,那么此时包含sk−1s_{k-1}sk−1的所有路径,就是u,v都断开uv这条路径上的边后,所在的联通块中各选一点,设断开后联通块大小分别a,b,那么路径数就是a×ba\times ba×b。

那么这个过程可以dpdpdp,f(u,v)f(u,v)f(u,v)表示当前选中的链是路径(u,v)(u,v)(u,v),在这条链上,设长度为k的话,已经放了0,k−10,k-10,k−1这些点,此时的∑i=0k−1∑pp包含si\sum_{i=0}^{k-1}\sum_pp包含s_i∑i=0k−1∑pp包含si的最大值。

由于能选中的路径不同,需要考虑一个dp,维护所有路径的答案,取最大值。这里n=2000,允许O(n2)O(n^2)O(n2)的dp。转移就枚举u,vu,vu,v不在路径(u,v)(u,v)(u,v)上的邻居,采用刷表,每次拓展一个点。

这类似于树上的区间dp。因为转移顺序必须按照链长度转移,计算长度k的链之前,必须把所有长度k-1的链都算完。我们考虑先做一个dfs,把链按照长度收集,然后按长度升序枚举所有链。

转移中还需要知道,uv的邻居中哪个是在路径(u,v)上的,以及排除掉这个在路径上的邻居后,剩余联通块的大小。对于u,这等价于以v为根时,求u的父亲,以及u子树的大小,这可以以每个点为根,分别dfs,在O(n2)O(n^2)O(n2)的复杂度解决。这和前面按照长度收集所有路径都需要以每个点为根的dfs,可以放一起做。

c 复制代码
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int MAXN = 2005;

// 邻接表与树拓扑信息
vector<int> adj[MAXN];
int depth[MAXN][MAXN]; // depth[r][u]: 以 r 为根时 u 的深度(即 u 到 r 的路径距离)
int parent[MAXN][MAXN];// parent[r][u]: 以 r 为根时 u 的父节点
int sz[MAXN][MAXN];    // sz[r][u]: 以 r 为根时 u 的子树大小
int degree[MAXN];

// 按路径距离(边数)分类的点对集合
vector<pair<int, int>> pairs_by_dist[MAXN];

// DP 数组及全局答案
long long dp[MAXN][MAXN];
long long max_score;

// 更新最大值的辅助函数
inline void update_max(long long &x, long long y) {
    if (x < y) x = y;
}

// 预处理以 root 为根的 DFS 信息
void dfs(int root, int u, int p, int d) {
    depth[root][u] = d;
    parent[root][u] = p;
    sz[root][u] = 1;

    // 将点对 (root, u) 按距离挂载到对应的桶中
    pairs_by_dist[d].push_back({root, u});

    for (int v : adj[u]) {
        if (v != p) {
            dfs(root, v, u, d + 1);
            sz[root][u] += sz[root][v];
        }
    }
}

void solve() {
    int n;
    cin >> n;

    // 1. 重置与清空数据
    max_score = 0;
    int max_degree = 0;
    for (int i = 1; i <= n; ++i) {
        adj[i].clear();
        pairs_by_dist[i - 1].clear();
        degree[i] = 0;
        fill(dp[i], dp[i] + n + 1, 0);
    }

    // 2. 建图
    for (int i = 0; i < n - 1; ++i) {
        int u, v;
        cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
        degree[u]++;
        degree[v]++;
    }

    for (int i = 1; i <= n; ++i) {
        max_degree = max(max_degree, degree[i]);
    }

    // 3. 计算最小值
    // 树为链时最小分数为 2N-1;非链树通过破坏第三个标签的共线性,最小分数恒为 N+1
    long long min_score = (max_degree <= 2) ? (2LL * n - 1) : (n + 1);

    // 4. 以每个节点为根全量 DFS 预处理树形态
    for (int r = 1; r <= n; ++r) {
        dfs(r, r, 0, 0);
    }

    // 5. 初始化 DP 基础状态:边界 dp(u, u) = F({u})
    for (auto& p : pairs_by_dist[0]) {
        int u = p.first;
        long long single_contrib = 1;
        long long current_sum = 1;

        for (int v : adj[u]) {
            single_contrib += current_sum * sz[u][v];
            current_sum += sz[u][v];
        }
        dp[u][u] = single_contrib;
    }

    // 6. 按距离从小到大(刷表法 Push DP)拓展路径
    for (int dist = 0; dist < n; ++dist) {
        for (auto& path : pairs_by_dist[dist]) {
            int u = path.first;
            int v = path.second;

            update_max(max_score, dp[u][v]);

            // 向 u 的外侧扩展邻居节点 z
            for (int z : adj[u]) {
                // 必须保证 z 不在 u->v 的路径上(即 z 不为以 v 为根时 u 的父节点)
                if (z != parent[v][u]) {
                    int l = min(v, z);
                    int r = max(v, z);
                    // 刷表转移:dp(u, v) -> dp(z, v)
                    update_max(dp[l][r], dp[u][v] + 1LL * sz[u][z] * sz[z][v]);
                }
            }

            // 向 v 的外侧扩展邻居节点 z
            for (int z : adj[v]) {
                // 必须保证 z 不在 v->u 的路径上(即 z 不为以 u 为根时 v 的父节点)
                if (z != parent[u][v]) {
                    int l = min(u, z);
                    int r = max(u, z);
                    // 刷表转移:dp(u, v) -> dp(u, z)
                    update_max(dp[l][r], dp[u][v] + 1LL * sz[v][z] * sz[z][u]);
                }
            }
        }
    }

    cout << min_score << " " << max_score << "\n";
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int t;
    if (cin >> t) {
        while (t--) {
            solve();
        }
    }
    return 0;
}

1010

扫描线 前缀和 取模

对一个序列,求所有子区间的权值和。一个子区间的权值定义为,对区间做任意次操作,每次操作把两个相邻元素删掉,变成他们的和模三,再插入。直到变成字典序最小的形式,把这个结果看成一个三进制数,就是权值,从左往右看成三进制从低位到高位。

对所有区间求和,n=2e5,不能枚举区间,一般考虑枚举区间右端点,维护前缀和信息,对于每个右端点,利用前缀和算出他和所有可能左端点的贡献。

本题也这样考虑。维护模3的前缀和sis_isi。枚举rrr,根据sr−sl(mod3)s_r-s_l \pmod 3sr−sl(mod3)的值,也就是子区间的和模3的结果分类讨论

  • 如果为0,字典序最小的方案就是合成一个0,方案可能有很多,但对答案的贡献都是0,忽略
  • 如果为1那么字典序最小的方案是,前面合成尽量多的0,最后一段合成一个1,因为按字典序00001是比01要小的。对于一个rrr,多个lll,每个的贡献是一个3∗x3*x3∗x的形式,xxx是这个lll后面还有多少个余数相同的位置,每有一个都可以合成一个0,由于三进制从左往右,是从低位到高位,也就使得最后那个1的权重变高。举个例子就是01,001,001这样的序列,贡献是3,9,27。对于这样的贡献,可以用一个等比数列求和,只要知道有多少个lll,满足sr−sl(mod3)=1s_r-s_l\pmod 3=1sr−sl(mod3)=1,设有x个,那么总贡献就是∑i=1x3x−i=1+3+⋯+3x−1=3x−12\sum_{i=1}^{x}3^{x-i} =1+3+\cdots+3^{x-1} =\frac{3^x-1}{2}∑i=1x3x−i=1+3+⋯+3x−1=23x−1。
  • 如果余数为2,可以类似的0002,前面若干个0,最后一段合成2.但这样不是字典序最小的,实际上00010001这样才是最优的,第一段0的个数,是lll右侧到rrr之前,和lll余数相同的个数,这些都可以合成0。最后一段和的余数为2,可以先找到第一个余数1的位置合成一个1,然后类似的,尽量多的合成0,直到最后一段合成1。
    具体分析,sl=sr−2(mod3)s_l=s_r-2\pmod 3sl=sr−2(mod3),等价于sl=sr+1(mod3)s_l=s_r+1\pmod 3sl=sr+1(mod3)。这里第一个1的位置i,应该满足si=sl+1(mod3)s_i=s_l+1\pmod 3si=sl+1(mod3),接下我们需要知道这个1右侧能合成的0个数,就是右侧相同余数的位置数。对于这个东西,我们不止要保存前缀和的每种余数的出现次数cnt,还需要保存前缀和的每种余数,上一次出现时,的出现次数,也就是对cnt数组做一个快照last_cnt。这样查last_cnt,即可得到第一个1后面,还有多少个余数相同的位置,也就知道第二段0的长度,设为y,之前第一段0的个数,设为x。那么这个子区间的贡献为3x(1+3y)3^x(1+3^y)3x(1+3y)
    对于多个lll,xxx是等差数列,yyy是相同的,因此可以把(1+3y)(1+3^y)(1+3y)提出来,剩下的部分仍然是∑i=1x3x−i=1+3+⋯+3x−1=3x−12\sum_{i=1}^{x}3^{x-i} =1+3+\cdots+3^{x-1} =\frac{3^x-1}{2}∑i=1x3x−i=1+3+⋯+3x−1=23x−1。

这些都分析清楚了,只需要为互一个前缀和余数的计数数组cnt,以及一个计数数组的历史版本(对每种余数,上次出现时的cnt数组快照)

c 复制代码
#include <iostream>
#include <vector>

using namespace std;

const int MOD = 998244353;
const int INV_TWO = (MOD + 1) / 2; // 2 在模 MOD 意义下的逆元 (499122177)

void solve() {
    int n;
    cin >> n;

    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    // 预处理 3 的幂次数组
    vector<int> pow3(n + 1, 1);
    for (int i = 1; i <= n; ++i) {
        pow3[i] = 1LL * pow3[i - 1] * 3 % MOD;
    }

    // count[r]: 到目前为止,前缀余数 r 出现的总次数(初始 S_0 = 0 算 1 次)
    int count[3] = {1, 0, 0};
    
    // last_count[s][m]: 上一次出现余数 s 的瞬间,余数 m 的历史出现次数
    int last_count[3][3] = {0};

    int cur_sum = 0; // 当前前缀和模 3
    long long ans = 0;

    for (int r = 0; r < n; ++r) {
        cur_sum = (cur_sum + a[r]) % 3;

        // ------------------ 1. 统计余数差为 1 的情况 ------------------
        int s1 = (cur_sum + 2) % 3; // 所需左端点余数 s1
        int cnt1 = count[s1];       // 符合条件的左端点个数 x

        if (cnt1 > 0) {
            // 所有左端点 3^z 的等比数列和: (3^x - 1) / 2
            long long geom1 = 1LL * (pow3[cnt1] - 1 + MOD) * INV_TWO % MOD;
            ans = (ans + geom1) % MOD;
        }

        // ------------------ 2. 统计余数差为 2 的情况 ------------------
        int s2 = (cur_sum + 1) % 3; // 所需左端点余数 s2
        int m2 = (s2 + 1) % 3;      // 中转点余数 m2
        int cnt2 = count[s2];       // 符合条件的左端点个数 x

        if (cnt2 > 0) {
            // 所有左端点 3^z 的等比数列和
            long long geom2 = 1LL * (pow3[cnt2] - 1 + MOD) * INV_TWO % MOD;
            
            // 下标统一:m2 当前总次数 - 上一次出现 s2 时 m2 的历史次数
            int c = count[m2] - last_count[s2][m2];
            
            // 计算公共系数 (1 + 3^c)
            long long factor = (pow3[c] + 1) % MOD;

            ans = (ans + geom2 * factor) % MOD;
        }

        // ------------------ 3. 更新历史快照与频次 ------------------
        // 当遇到当前余数 cur_sum 时,存下此时所有余数 m 的快照
        for (int m = 0; m < 3; ++m) {
            last_count[cur_sum][m] = count[m];
        }
        
        // 累加当前余数的频次
        count[cur_sum]++;
    }

    cout << ans << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    if (cin >> t) {
        while (t--) {
            solve();
        }
    }
    return 0;
}

1012

二分图

给一个可以黑白染色的图,问k元环的个数,k是质数。

可以黑白染色意味着二分图,二分图只有偶环。由于k是质数,只有k=2时才是偶环,其他情况k都是奇数,k元环都不存在。

对于k=2,实际上只有重边能组成,一个位置有xxx个重边,能构成x(x−1)/2x(x-1)/2x(x−1)/2个2元环。统计重边即可。

相关推荐
奈斯先生Vector16 分钟前
从“能调用”到“可运营”:AI Agent 进入多模型时代后的架构升级
java·javascript·数据库·人工智能·算法·架构·aigc
2601_9561219727 分钟前
Bellman-ford算法
算法
叠层归一研究院34 分钟前
基于区分本源的此刻存在唯一性本体论推演
人工智能·算法
luj_176834 分钟前
尾椎藏今生记忆?骨盆对应不确定性
开发语言·网络·c++·经验分享·算法
深圳多奥智能一卡(码、脸)通系统36 分钟前
智能梯控SDK可直接用于第三方开发对接的接口文档说明书
服务器·前端·算法
Chester_19999 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
裕晟资质规划10 小时前
武器装备科研生产单位保密资质申请方法论:条件模型与流程拆解
人工智能·算法
en.en..11 小时前
C语言 标准输入 / 输出缓冲区
算法