10.24

考前挂分是个好迹象,至少不像啥也不会那么绝望是不是/

A.城市间交通

第一眼整体二分+可撤销并查集,觉得有点难写,而且两个 \(\log\)
再看一眼,发现最小生成树+倍增优秀单 \(\log\) 做法。

显然这种路径 \(\max\) 的先建个最小生成树啊,然后倍增一下就知道路径 \(\max\) 了,最后按边权从小到大连个边就知道每个连通块的大小了。

B.最小公倍数

第一眼这不是我们 P3911 最小公倍数之和 吗?
坏消息是忘了怎么莫反了。
于是写了个跟数学无关的两个 \(\log\) 普及组写法。

考虑设 \(f_{i,k}\) 为满足 \(\gcd(i,j)=k\)\(j\) 的和,那么我们可以枚举 \(i\) 的倍数来求,但是 \(\gcd\) 可能不是 \(k\),所以要减去 \(\gcd=2k,3k,\dots,nk\) 的情况,倒着 \(dp\) ,每次枚举 \(k\) 的因数提前减去就好。

点击查看代码
#include <bits/stdc++.h>
#define LL long long
#define pb push_back
 
using namespace std;
 
inline int read()
{
	LL x = 0,f = 1;char ch = getchar();
	while(!isdigit(ch)) (ch == '-') && (f = -1),ch = getchar();
	while(isdigit(ch)) x = x*10+ch-48,ch = getchar();
	return x*f;
}

const int N = 50010;
int c[N];
LL s[N],f[N];
vector < int > d[N];

int main()
{
	for (int i = 1;i <= 5e4;i++)
		for (int j = i;j <= 5e4;j += i) d[j].pb(i);
	int n = read();
	for (int i = 1;i <= n;i++) c[read()]++;
	for (int i = 1;i <= 5e4;i++)
	{
		reverse(begin(d[i]),end(d[i]));
		for (int j = i;j <= 5e4;j += i) s[i] += 1LL*j*c[j];
	}
	LL ans = 0;
	for (int i = 1;i <= 5e4;i++)
	{
		for (int x : d[i])
		{
			f[x] += s[x];
			for (int j = 1;j < d[x].size();j++)	f[d[x][j]] -= f[x];
			ans = ans+1LL*i/x*c[i]*f[x];
		}
		for (int x : d[i]) f[x] = 0;
	}
	cout << ans;
	return 0;
}

C.衍生命题

应该没写挂,但是读错题了,写了个优秀的 线段树优化建图+线段树合并+可持久化线段树,拼在一块码量还挺小的。
所以代数之差里的代,为什么不是代数的代,而是第几代的代?

建一棵 \(\text{dfn}\) 序的线段树,每个节点维护一个按深度从小到大排序的 \(\text{vector}\),相邻大数往小数连边优化建图就完了。

posted @ 2024-10-24 15:21  ZepX_D  阅读(46)  评论(0)    收藏  举报