[2017纪中11-2]失格 最小生成树+数论

来源:互联网 发布:mac os 终端命令 编辑:程序博客网 时间:2024/06/02 06:20

题面
正解
考场100pts乱搞做法:
首先先去重。
最小生成树从小到大加进边去是没有问题的,于是考虑枚举边长(余数)k,再枚举数a[i],再枚举倍数j,如果a[i]*j+k存在,则连一条边长为k的边,直到合并成数为止。
复杂度O(maxk*nlogP),不知道为什么跑得飞快,比O(nlogP)的正解跑的还快,貌似maxk *n大概是P级别的,此消彼长的那种。。。再加上常数小吧。。。加上x%y<=x%(k *y)的优化跑的更快了。。。
不加优化代码:

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#define ll long longusing namespace std;const int maxn=100010;int n,fa[10000010],size[10000010],mxp=0,cnt,a[maxn];bool vis[10000010];ll ans;struct edge{    int x,y,w;}e[1000010];bool cmp(edge a,edge b){    return a.w<b.w;}int getfa(int v){    if(fa[v]==v) return v;    fa[v]=getfa(fa[v]);    return fa[v];}bool merge(int x,int y){    if(getfa(x)==getfa(y)) return 0;    if(size[fa[x]]<size[fa[y]]) swap(x,y);    size[fa[x]]+=size[fa[y]];    fa[fa[y]]=fa[x];    return 1;}int read(){    int x=0;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}    return x;}void work(){    cnt=0;ans=0;    for(int k=0;k<=mxp&&cnt<n-1;k++)        for(int i=1;i<=n;i++)                for(int j=1;a[i]*j+k<=mxp;j++)                    if(fa[a[i]*j+k]!=0&&merge(a[i],a[i]*j+k)) cnt++,ans+=k; }int main(){    n=read();    for(int i=1;i<=n;i++)    {        int x=read();        mxp=max(mxp,x);        fa[x]=x;size[x]=1;    }    n=0;    for(int i=1;i<=mxp;i++)        if(fa[i]!=0) a[++n]=i;      work();    printf("%lld",ans);    return 0;           }

加优化代码:

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#define ll long longusing namespace std;const int maxn=100010;int n,fa[10000010],size[10000010],mxp=0,cnt,a[maxn];bool vis[10000010];ll ans;struct edge{    int x,y,w;}e[1000010];bool cmp(edge a,edge b){    return a.w<b.w;}int getfa(int v){    if(fa[v]==v) return v;    fa[v]=getfa(fa[v]);    return fa[v];}bool merge(int x,int y){    if(getfa(x)==getfa(y)) return 0;    if(size[fa[x]]<size[fa[y]]) swap(x,y);    size[fa[x]]+=size[fa[y]];    fa[fa[y]]=fa[x];    return 1;}int read(){    int x=0;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}    return x;}void work(){    cnt=0;ans=0;    for(int i=1;i<=n&&cnt<n-1;i++)        for(int j=2;a[i]*j<=mxp;j++)            if(fa[a[i]*j]!=0&&merge(a[i],a[i]*j))                 cnt++,vis[a[i]*j]=1;    int top=0;              for(int i=1;i<=mxp;i++)        if(fa[i]!=0&&vis[i]==0) a[++top]=i;     for(int k=1;k<=mxp&&cnt<n-1;k++)        for(int i=1;i<=top;i++)            for(int j=1;a[i]*j+k<=mxp;j++)                if(fa[a[i]*j+k]!=0&&merge(a[i],a[i]*j+k))                         cnt++,ans+=k;}int main(){    n=read();    for(int i=1;i<=n;i++)    {        int x=read();        mxp=max(mxp,x);        fa[x]=x;size[x]=1;    }    n=0;    for(int i=1;i<=mxp;i++)        if(fa[i]!=0) a[++n]=i;      work();    printf("%lld",ans);    return 0;           }