比赛链接:

https://atcoder.jp/contests/abc243

E - Edge Deletion

题目大意:

\(n\) 个点,\(m\) 条边的无向图,第 \(i\) 条边长度为 \(c_i\),连接了点 \(a_i\)\(b_i\)。求出最多能删除多少条边,使剩下的图中任意两点间的最短距离和给定的图相同,同时剩下的图还要是连通的。

思路:

先通过 \(Floyed\) 求出任意两点间的最短距离,接着枚举每一条边,判断这条边是不是这两个点之间的最短距离,不是的话就将这条边删除。
判断的过程就是通过枚举其它所有点,判断有没有其他路径比这条路径短,注意,相同的时候也要删除,因为其他边可能是其它的一对点之间的最短距离,而当前这一条边可以通过其他路径代替。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 310, M = 5e4 + 10;
int n, m, d[N][N], u[M], v[M], w[M];
int main(){
	cin >> n >> m;
	memset(d, 0x3f, sizeof d);
	for (int i = 1; i <= n; ++ i)
		d[i][i] = 0;
	for (int i = 0; i < m; ++ i){
		scanf("%d%d%d", &u[i], &v[i], &w[i]);
		d[u[i]][v[i]] = w[i];
		d[v[i]][u[i]] = w[i];
	}
	for (int k = 1; k <= n; ++ k)
		for (int i = 1; i <= n; ++ i)
			for (int j = 1; j <= n; ++ j)
				d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
	int ans = 0;
	for (int i = 0; i < m; ++ i)
		for (int k = 1; k <= n; ++ k)
			if (u[i] != k && k != v[i] && d[u[i]][k] + d[k][v[i]] <= w[i]){
				ans++;
				break;
			}
	cout << ans << "\n";
	return 0;
}

G - Sqrt

题目大意:

给一个序列 \(A\),刚开始里面就一个元素 \(x\),定义这个序列的最后一个元素是 \(x\),每次可以选择 1 ~ \(\sqrt[]{x}\) 中任意一个数加入序列中,问可以形成多少个不同的序列。

思路:

原始的做法就是通过枚举 1 到 \(\sqrt[]{x}\) 所有数,记它为 \(j\),然后记忆化递归计算。O(\(\sqrt[]{x}\)) 的复杂度,超时
尝试再分解一次,对 \(\sqrt[]{x}\) 再进行一次递归分解操作。即通过枚举 \(i\),去分解 \(j\),有 \(\sqrt[]{x} - i * i + 1\)\(j\) 可以转化成同一个 \(i\),例如 5,6,7,8,最后开根号的值都是 2。复杂度降为 O(\(\sqrt[4]{x}\))。不用记忆化也能过。
ps:不要强制将 \(sqrt()\) 转成 \(long long\) 型,精度会出现问题。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T = 1, x;
LL mySqrt(LL x){
	LL k = sqrt(x) - 1;
	while ((k + 1) * (k + 1) <= x) k++;
	return k;
}
LL f(LL x){
	if (x == 1LL) return 1LL;
	LL ans = 0;
	for (LL i = 1; i * i * i * i <= x; ++ i)
		ans += f(i) * (mySqrt(x) - i * i + 1LL);
	return ans;
}
void solve(){
	cin >> x;
	cout << f(x) << "\n";
}
int main(){
	cin >> T;
	while (T--)
		solve();
	return 0;
}
posted on 2022-03-14 23:56  Hamine  阅读(43)  评论(0编辑  收藏  举报