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

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

#include
#include
#include
#include
#define ll long long
using 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.wint 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]]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&&cnt1;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
#include
#include
#include
#define ll long long
using 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.wint 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]]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&&cnt1;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&&cnt1;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;           
}

你可能感兴趣的:(数论,最小生成树)