PS:大家注意一下 蛤->拾 出题人打错了
A. 「NOIP模拟赛 蛤」ZigZagK的生成树
link
solve
这道题我们要抓住一个性质,如果(a)可以被(b)整除,则(gcd(a,b)=b),所以我们建边是要和他的最大约数建边,质数就和1建边,我们可以从大到小枚举约数,去连他的倍数,但我们发现,一个数可能被链接多次,产生环,用并查就可以判断是否出现环,有点像Kruskal一样,由于约数是从大到小来枚举的,所以就不用排序了,这里要注意一个结论(1+frac{1}{2}+frac{1}{3}+frac{1}{4}+...+ frac{1}{n}=ln(n)+R),其中(R)是欧拉常数,值为(0.57721566490)左右。所以时空复杂度约为(O(nln(n)))
code
#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline void read(LL &x)
{
LL f=1;x=0;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<3)+(x<<1)+(ch&15);ch=getchar();}
x*=f;
}
LL n,cnt=0,fa[1000005],ans=0;
inline LL getfa(LL x){if (x==fa[x]) return x;return fa[x]=getfa(fa[x]);}
int main()
{
read(n);
for (LL i=1;i<=n;i++) fa[i]=i;
for (LL i=n;i>=1;i--)
for (LL j=2;j<=n/i;j++)
{
LL fx=getfa(i),fy=getfa(i*j);
if (fx!=fy) {fa[fx]=fy,ans+=i,cnt++;if (cnt==n-1) break;}
}
cout<<ans<<endl;
return 0;
}
B. 「NOIP模拟赛 蛤」Lynstery的生成树
link
solve
话说这道题的描述是真的坑,我读了一个半小时才搞懂题目在干嘛,简化的来说,就是给出一个图,找任意个基环树,使得边权加和最大,我们用一个贪心的想法,从边权最大的地方开始取,用并查集来判断哪些节点是在一棵树里面的,每棵树最多只有一个圈,我们可以开一个(h[])数组来记录是否有环,如果有两个环了就不连接了。
代码还是很好实现的。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int N,M,fa[100005],h[100005];
long long ans;
struct AS{
int x,y,w;
bool operator <(const AS B)const {return w>B.w;}
}a[100005];
inline int read() {
int f=1,x=0;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while('0'<=ch&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
int main(){
// freopen("2.in","r",stdin);
// freopen("2.out","w",stdout);
N=read();M=read();
for(int i=1;i<=M;i++)a[i].x=read(),a[i].y=read(),a[i].w=read(),fa[i]=i;
sort(a+1,a+1+M);
for(int i=1;i<=M;i++){
int fx=get(a[i].x),fy=get(a[i].y);
if(fx==fy){
if(h[fx]!=0)continue;
ans+=(LL)a[i].w;
h[fx]=1;
}
else {
if(h[fx]==1&&h[fy]==1)continue;
else if(h[fx]==1){
fa[fy]=fx;
ans+=(LL)a[i].w;
}
else if(h[fy]==1){
fa[fx]=fy;
ans+=(LL)a[i].w;
}
else {
fa[fx]=fy;
ans+=(LL)a[i].w;
}
}
}
printf("%lld
",ans);
return 0;
}
C.「NOIP模拟赛 蛤」Axcosin的生成树
link
solve
你别被他的图骗了,其实就是一个线性问题,(想我就被骗了) 用贪心的想法,排序后,最大的和最小的匹配,如果超过S就抵消掉,如果没有超过S就往里面推,那个图就是一个幌子,还是一个数字匹配的问题,哎wtcl。
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int n,m,a[maxn],ans;
bool vis[maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-f;ch=getchar();}
while (ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
return ret*f;
}
int main(){
n=read();m=read();
for (int i=1;i<=n;i++) a[i]=read();
sort(a+1,a+n+1);int R=n;
for (int i=1;i<R;i++){
if (a[i]+a[R]>=m) R--,ans++;
}
printf("%d
",ans);
return 0;
}