【JZOJ 5445】【NOIP2017提高A组冲刺11.2】失格

来源:互联网 发布:rs485端口电压高 编辑:程序博客网 时间:2024/06/05 19:04

Description

胆小鬼连幸福都会害怕,碰到棉花都会受伤,有时还被幸福所伤。
——太宰治《人间失格》

回顾我的一生,一共有n个事件,每一个事件有一个幸福值p_i。
我想用n-1条线把所有的事件连起来,变成一个连通块。一条连接了事件x和事件y的线会产生min(p_x mod p_y,p_y mod p_x)的喜悦值。
日日重复同样的事,遵循着与昨日相同的惯例,若能避开猛烈的狂喜,自然也不会有悲痛的来袭。因此,我想知道连接起来之后产生喜悦值最小是多少。

Solution

显然,相同的可以直接合并,
对于每一个ai枚举倍数k,对于aj,满足kaiaj<(k+1)ai,那么这些数,只有最小的一个是可能与i有边相连的,
那么直接预处理,排序后做Kruscal即可,不过由于边太多了,要用桶排,

复杂度:O(107log(107))

Code

我的程序为正解的阉割版,很难卡掉,但空间极其小(然并卵)

#include <cstdio>#include <algorithm>#include <queue>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)using namespace std;typedef long long LL;const int N=100500,mo=998244353;int read(int &n){    int w=1;char ch=' ';n=0;    for(;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());    if(ch=='-')ch=getchar(),w=-1;    for(;ch<='9'&&ch>='0';ch=getchar())n=n*10+ch-48;    return n=n*w;}int n,m,ans;int a[N];int d[N][2],d0;int g[N],bv[N];bool z[N];struct qqww{    int v,i;    friend bool operator <(qqww q,qqww w){return q.v>w.v;}};priority_queue<qqww> Ds;int gf(int q){return g[q]==q?q:(g[q]=gf(g[q]));}bool PX(int q,int w){return q>w;}int FD(int q,int t){    while(a[q]<t)    {        int i=1;        for(;(i<<1)<=q&&a[q-(i<<1)]<=t;i<<=1);        q-=i;    }    return q;}void PRE(){    fo(i,2,n)    {        // printf("%d\n",i);        int t=a[i];bv[i]=2e9;        for(int j=FD(i-1,t);j>0;t+=a[i],j=FD(j-1,t))        {            if(a[j]-t>=a[i])            {                for(t=(a[j]/a[i])*a[i];a[j]-t>=a[i];t+=a[i]);            }            if(bv[i]>a[j]-t)            {                bv[i]=a[j]-t;                if(!bv[i])break;            }        }        qqww t1;t1.i=i;t1.v=bv[i];        Ds.push(t1);    }}int main(){       freopen("autosadism.in","r",stdin);    freopen("autosadism.out","w",stdout);    int q,w;    read(n);    fo(i,1,n)read(a[i]);    sort(a+1,a+1+n,PX);a[0]=2e9;    if(a[n]<2){printf("0\n");return 0;}    q=0;    fo(i,2,n)    {        a[i-q]=a[i];        if(a[i]==a[i-q-1])q++;    }    n-=q;    ans=0;    fo(i,1,n)g[i]=i;    PRE();    for(int I=1;I<n;)    {        // printf("%d\n",I);        q=(Ds.top()).i;Ds.pop();        int t=a[q],bt=bv[q];bv[q]=2e9;        gf(q);        for(int j=FD(q-1,t);j>0;t+=a[q],j=FD(j-1,t))        {            if(a[j]-t>=a[q])            {                for(t=(a[j]/a[q])*a[q];a[j]-t>=a[q];t+=a[q]);            }            if(g[q]!=gf(j))            {                if(a[j]-t<=bt)                {                    I++;                    ans+=bt;                    g[gf(q)]=g[j];                    gf(q);                }else if(bv[q]>a[j]-t)bv[q]=a[j]-t;            }        }        qqww t1;t1.i=q;t1.v=bv[q];        if(bv[q]<1e9)Ds.push(t1);    }    printf("%d\n",ans);    return 0;}
原创粉丝点击