[题解]CodeChef JUNE Challenge 17

来源:互联网 发布:金十数据如何看原油 编辑:程序博客网 时间:2024/06/05 06:42

这次比赛打的很有趣啊。
Challenge大战!

A Good Set

题意简述

定义“好集合”为:集合中元素两两不同,权值均在[1,500],且不存在三个元素a,b,c使得a+b=c
输出大小为n的“好集合”

数据范围

1T,n100

思路

一开始想二进制之类的balabala……
最后发现输出最大的前n个数不就行了……
Naive!

代码

    #include<bits/stdc++.h>    using namespace std;    template<typename T>    void read(T &x)    {        char ch=getchar();        for (x=0;ch<'0'||ch>'9';ch=getchar());        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());    }    int T,n;    int main()    {        read(T);        while (T--)        {            read(n);            for (int i=1;i<=n;i++)                printf("%d%c",501-i," \n"[i==n]);        }        return 0;    } 

Xenny and Coin Rankings

题意简述

给二维坐标定义了一个序。
大体图形是这样子的:

74218539610

然后问你一个矩形范围内标号最大的点是多少。

数据范围

1T100
1u,v109

思路

标号最大的肯定是右上角的啊…
公式题。

代码

    #include<bits/stdc++.h>    using namespace std;    template<typename T>    void read(T &x)    {        char ch=getchar();        for (x=0;ch<'0'||ch>'9';ch=getchar());        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());    }    typedef long long ll;    int T,u,v,x;    ll ans;    int main()    {        read(T);        while (T--)        {            read(u),read(v);            x=u+v;            ans=1LL*(1+x)*x/2;            ans+=u+1;            printf("%lld\n",ans);        }        return 0;    } 

Chef and the Feast

题意简述

n盘菜,每盘菜有美味度ai,你可以分若干次吃完。
每次吃,假设吃掉k盘,你将获得ki=1ai×k的幸福度。
最大化幸福度之和。

数据范围

1T8
1n105
0|ai|108

思路

贪心。
一开始想的正的都在一起选,负的一个一个选。
wawawawawa。
后来撕烤了一下。
猜了个结论:一起选的一定是从大到小连续的一段区间,剩下的单独选。
排序,从大到小选,如果加上这盘菜还能使答案>0就选……
正确性证明见wa爷爷blog:http://wronganswer.blog.uoj.ac/blog/2667

代码

    #include<bits/stdc++.h>    using namespace std;    template<typename T>    void read(T &x)    {        char ch=getchar();        int f=1;        for (x=0;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());        if (ch=='-') f=-1,ch=getchar();        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());        x*=f;    }    typedef long long ll;    int T,n;    int seq[100010];    ll u,sum,ans,size;    int main()    {        read(T);        while (T--)        {            read(n);            for (int i=1;i<=n;i++)                read(seq[i]);            sort(seq+1,seq+n+1);            sum=0,ans=0,size=0;            for (int i=n;i>=1;i--)                if (seq[i]*size+sum >=0)                    sum+=seq[i],size++;                else                {                    for (int j=i;j>=1;j--)                        ans+=seq[j];                    break;                }            ans+=sum*size;            printf("%lld\n",ans);        }        return 0;    } 

Pairwise union of sets

题意简述

给你n个集合。
每个集合的元素[1,k]
问有多少对集合,它们的并集为1k的全集。

数据范围

1T10
1n,k2500
sizei10000

思路

看到题第一感随手打了个bitset…
TLE……
加了个优化,如果两个集合的size之和都到不了k就不计算它们的并。
TLE……
随眼一瞟看到元素个数之和10000
按照k大小分类,小的就bitset开小一点……
然后就A了……
O(Tmin(n2,(10000k2)2)k64)
然后就过了……

代码

    #include<bits/stdc++.h>    using namespace std;    template<typename T>    void read(T &x)    {        char ch=getchar();        for (x=0;ch<'0'||ch>'9';ch=getchar());        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());    }    int T,n,k,ans,u,v;    int num[2510];    void work1000()    {        bitset<2510> B[2510];        for (int i=1;i<=n;i++)            B[i].reset();        memset(num,0,sizeof(num));        for (int i=1;i<=n;i++)        {            read(u);            for (int j=1;j<=u;j++)            {                read(v);                B[i].set(v);                num[i]++;            }        }        ans=0;        for (int i=1;i<=n;i++)            for (int j=i+1;j<=n;j++)                if (num[i]+num[j]>=k && (B[i]|B[j]).count()==k)                    ans++;        printf("%d\n",ans);    }    void work100()    {        bitset<110> B[2510];        for (int i=1;i<=n;i++)            B[i].reset();        memset(num,0,sizeof(num));        for (int i=1;i<=n;i++)        {            read(u);            for (int j=1;j<=u;j++)            {                read(v);                B[i].set(v);                num[i]++;            }        }        ans=0;        for (int i=1;i<=n;i++)            for (int j=i+1;j<=n;j++)                if (num[i]+num[j]>=k && (B[i]|B[j]).count()==k)                    ans++;        printf("%d\n",ans);    }    int main()    {        read(T);        while (T--)        {            read(n),read(k);            if (k<=100)                work100();            else                work1000();        }        return 0;    }  

Triplets

题意简述

给定三个序列A,B,Cf(x,y,z)=(x+y)(y+z)[xy][zy]
i,j,kf(Ai,Bj,Ck)

数据范围

1T10
1n105

思路

two pointers。
都排序之后枚举ji,k相应移动即可。

代码

    #include<bits/stdc++.h>    using namespace std;    template<typename T>    void read(T &x)    {        char ch=getchar();        for (x=0;ch<'0'||ch>'9';ch=getchar());        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());    }    typedef long long ll;    #define MAXN 100010    const int mo=1000000007;    int T,a,b,c;    int A[MAXN],B[MAXN],C[MAXN];    ll suma,sumc,ans;    int main()    {        read(T);        while (T--)        {            read(a),read(b),read(c);            for (int i=1;i<=a;i++)                read(A[i]);            for (int i=1;i<=b;i++)                read(B[i]);            for (int i=1;i<=c;i++)                read(C[i]);            sort(A+1,A+a+1);            sort(B+1,B+b+1);            sort(C+1,C+c+1);            suma=0,sumc=0,ans=0;            for (int i=1,j=1,k=1;j<=b;j++)            {                while (i<=a && A[i]<=B[j]) suma=(suma+A[i++])%mo;                while (k<=c && C[k]<=B[j]) sumc=(sumc+C[k++])%mo;                ans=(ans+1LL*(i-1)*(k-1)%mo*B[j]%mo*B[j] + suma*(k-1)%mo*B[j] + sumc*(i-1)%mo*B[j] + suma*sumc)%mo;            }            printf("%lld\n",ans);        }        return 0;    } 

Chef and Prime Queries

题意简述

给出长度为n的数列A
Ai=pk11pk22
每次询问Ri=Lpkk[xpy]

数据范围

1n,q105
1ai,x,y106

思路

稍微转化一下就会发现这是一个矩形和问题。
离线询问,将每个询问拆成L,R两个,拆分之后的询问就变成了[x,y]区间已有的质数个数累加和是多少。
排序。顺序扫描A,添加质数,回答询问。
质因子个数d7
总复杂度O(Td(q+n)logn)

代码

#include<bits/stdc++.h>using namespace std;template<typename T>void read(T &x){    char ch=getchar();    for (x=0;ch<'0'||ch>'9';ch=getchar());    for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());}int n,q,t1,t2,t3,t4,Q_cnt,now,tmp;int a[100010],ans[100010];int p_cnt,prime[100010],mn[1000010],go[1000010],ti[1000010],idx[1000010];bool not_p[1000010];void sieve(int n){    not_p[1]=1;    for (int i=2;i<=n;i++)    {        if (!not_p[i])        {            prime[++p_cnt]=i;            mn[i]=p_cnt;            go[i]=1;            ti[i]=1;        }        for (int j=1;i*prime[j]<=n && j<=p_cnt;j++)        {            not_p[i*prime[j]]=1;            if (i%prime[j]==0)            {                mn[i*prime[j]]=mn[i];                go[i*prime[j]]=go[i];                ti[i*prime[j]]=ti[i]+1;                break;            }            mn[i*prime[j]]=j;            go[i*prime[j]]=i;            ti[i*prime[j]]=1;        }    }    p_cnt=0;    for (int i=1;i<=n;i++)    {        if (!not_p[i]) p_cnt++;        idx[i]=p_cnt;    }}struct BIT{    static const int size=100000;    int d[100010];    BIT()    {        memset(d,0,sizeof(d));    }    int lowbit(int x)    {        return x&(-x);    }    void modify(int pos,int val)    {        for (;pos<=size;pos+=lowbit(pos))            d[pos]+=val;    }    int query(int l,int r)    {        int ret=0;        for (;r;r-=lowbit(r))            ret+=d[r];        for (;l;l-=lowbit(l))            ret-=d[l];        return ret;    }}T;struct Query{    int pos,x,y,ty,id;    Query(int _pos=0,int _x=0,int _y=0,int _ty=0,int _id=0)    {        pos=_pos,x=_x,y=_y,ty=_ty,id=_id;    }    bool operator < (const Query &n1) const    {        return pos<n1.pos;      }    void print()    {        printf("pos=%d,[%d,%d],id=%d\n",pos*ty,x,y,id);    }}Q[200010];int main(){    sieve(1000000);    read(n);    for (int i=1;i<=n;i++)        read(a[i]);    read(q);    for (int i=1;i<=q;i++)    {        read(t1),read(t2),read(t3),read(t4);        Q[++Q_cnt]=Query(t1-1,idx[t3-1],idx[t4],-1,i);        Q[++Q_cnt]=Query(t2,idx[t3-1],idx[t4],1,i);    }    sort(Q+1,Q+Q_cnt+1);    now=1;    for (int i=1;i<=Q_cnt;i++)    {        while (now<=Q[i].pos)        {            tmp=a[now];            while (tmp!=1)            {                T.modify(mn[tmp],ti[tmp]);                tmp=go[tmp];            }            now++;        }        ans[Q[i].id]+=Q[i].ty*T.query(Q[i].x,Q[i].y);    }    for (int i=1;i<=q;i++)        printf("%d\n",ans[i]);    return 0;}

Cloning

题意简述

定义两个长度相等的子串是“相似的”:将它们的元素分别排序后,一一对应,最多只有一位不同。
给出长度为n的数列A
每次询问两个长度相等子串是否是相似的。

数据范围

1T3
1n,Ai105

思路

hash+主席树。
按照权值哈希,权值为x的元素对哈希值的贡献为basex
在主席树上,两个区间一起跑,找到哈希相同的最大前缀和最大后缀。
判断一下即可。

代码

        #include<bits/stdc++.h>        using namespace std;        template<typename T>        void read(T &x)        {            char ch=getchar();            for (x=0;ch<'0'||ch>'9';ch=getchar());            for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());        }        #define MAXN 100010        #define MAXV 100000        typedef unsigned long long ull;        const ull base=13331;        ull basepow[MAXN],val1,val2;        int T,n,q,l1,r1,l2,r2,posl,posr;        int seq[MAXN];        namespace PT        {            struct Node{                Node *ch[2];                ull sum;                void pushup()                {                    sum=ch[0]->sum+ch[1]->sum;                }            }*null=new Node;            Node pool[MAXN*30];            Node *tail=pool;            Node *NewNode()            {                Node *p=tail++;                p->ch[0]=p->ch[1]=null;                p->sum=0;                return p;            }            Node *Root[MAXN];            void init()            {                null->ch[0]=null->ch[1]=null;                null->sum=0;                tail=pool;                for (int i=0;i<=n;i++)                    Root[i]=NewNode();            }            void add(int pos,int l,int r,Node *node,Node *pre)            {                if (l==r)                {                    node->sum=pre->sum+basepow[pos];                    return;                }                int mid=(l+r)>>1;                if (pos<=mid)                {                    if (node->ch[0]==null)                        node->ch[0]=NewNode();                    node->ch[1]=pre->ch[1];                    add(pos,l,mid,node->ch[0],pre->ch[0]);                }                else                {                    if (node->ch[1]==null)                        node->ch[1]=NewNode();                    node->ch[0]=pre->ch[0];                    add(pos,mid+1,r,node->ch[1],pre->ch[1]);                }                node->pushup();            }            int queryl(int l,int r,Node *l1,Node *r1,Node *l2,Node *r2)            {                if (l==r) return l;                int mid=(l+r)>>1;                if (r1->ch[0]->sum - l1->ch[0]->sum != r2->ch[0]->sum - l2->ch[0]->sum)                    return queryl(l,mid,l1->ch[0],r1->ch[0],l2->ch[0],r2->ch[0]);                else                    return queryl(mid+1,r,l1->ch[1],r1->ch[1],l2->ch[1],r2->ch[1]);            }            int queryr(int l,int r,Node *l1,Node *r1,Node *l2,Node *r2)            {                if (l==r) return l;                int mid=(l+r)>>1;                if (r1->ch[1]->sum - l1->ch[1]->sum != r2->ch[1]->sum - l2->ch[1]->sum)                    return queryr(mid+1,r,l1->ch[1],r1->ch[1],l2->ch[1],r2->ch[1]);                else                    return queryr(l,mid,l1->ch[0],r1->ch[0],l2->ch[0],r2->ch[0]);            }            ull judge(int L,int R,int l,int r,Node *l1,Node *r1,Node *l2,Node *r2)            {                if (R<l || r<L) return 0;                if (L<=l && r<=R) return r1->sum - l1->sum + r2->sum - l2->sum;                int mid=(l+r)>>1;                return judge(L,R,l,mid,l1->ch[0],r1->ch[0],l2->ch[0],r2->ch[0])+judge(L,R,mid+1,r,l1->ch[1],r1->ch[1],l2->ch[1],r2->ch[1]);            }        }        int main()        {            basepow[0]=1;            for (int i=1;i<=100000;i++)                basepow[i]=basepow[i-1]*base;            read(T);                while (T--)            {                read(n),read(q);                PT::init();                for (int i=1;i<=n;i++)                {                    read(seq[i]);                    PT::add(seq[i],1,MAXV,PT::Root[i],PT::Root[i-1]);                }                for (int i=1;i<=q;i++)                {                    read(l1),read(r1),read(l2),read(r2);                    val1=PT::Root[r1]->sum - PT::Root[l1-1]->sum;                    val2=PT::Root[r2]->sum - PT::Root[l2-1]->sum;                    if (val1==val2)                        puts("YES");                    else                    {                        posl=PT::queryl(1,MAXV,PT::Root[l1-1],PT::Root[r1],PT::Root[l2-1],PT::Root[r2]);                        posr=PT::queryr(1,MAXV,PT::Root[l1-1],PT::Root[r1],PT::Root[l2-1],PT::Root[r2]);                        if ((posl+1>posr-1 || judge(posl+1,posr-1,1,MAXV,PT::Root[l1-1],PT::Root[r1],PT::Root[l2-1],PT::Root[r2])==0) && (val1+basepow[posl]==val2+basepow[posr] || val1+basepow[posr]==val2+basepow[posl]))                            puts("YES");                        else                            puts("NO");                    }                }            }            return 0;        }  

Euler Sum

题意简述

ni=1ie

数据范围

1n104000
代码长度限制1KB = =(真的大丈夫?

思路

首先语言肯定选个自带高精度的…现学了一下PY…
然后应该用什么算法呢…找了半天e的性质无果…
忘了墩爷还是YJQ随口一句类欧几里得…好嘛…现学一下类欧。
类欧好像有两种形式,一种是分数型ax+bc这样…然后你就转换一下枚举顺序balabala
另一种是一般型kx这样…然后你就每次讨论一下k>1就减掉一个下取整,否则就去取个倒数酱…
然后我就xjb用泰勒展开强行把e拟合成分数,跑了一下分数型…然后就过了…
考后想了下可不可以用ae+bce+dx这样的形式做,下取整和取倒数都很好实现,还没试……
吐槽一下PY还限制递归深度……

代码

    import sys    sys.setrecursionlimit(1000000000)    def solve(A,B,C,n):        if (A==0):            return (n+1)*(B//C)        if (A>=C):            return solve(A%C,B,C,n)+n*(n+1)//2*(A//C)        if (B>=C):            return solve(A,B%C,C,n)+(n+1)*(B//C)        m=(A*n+B)//C        return n*m-solve(C,C-B-1,A,m-1)    n=int(input())    C=1    A=1    lim=3000    for i in range (1,lim):        C*=i    for i in range (1,lim):        A=(A*i)+1    print(solve(A,0,C,n)) 

Persistent oak

题意简述

给你一棵树,树上每个节点都有一个重量承受度wi
当其子树的重量之和>wi,那么这棵子树就会断掉…如果有多个节点满足,选择最远离树根的节点。
有两个操作:
1.某个节点长出了重量为x的果实。
2.询问一棵子树内的果实数量,同时清空。
所有操作可持久化,每次操作会告诉你前驱版本的编号…

数据范围

1T10
1n,q105
1wi,x107

思路

先来考虑不持久化怎么做。
树链剖分,维护sum维护wisum的最小值维护一个加标记和一个清空标记。
1.操作就在链上跳,找到第一个满足要求的操作,子树清空,找不到就将到根的路径所有节点维护的那个最小值减去一个值。
2.子树查询sum,子树清空。
可持久化的话…加标记标记永久化一下。
清空的话…直接连到0号版本的树上(还有这种操作?.jpg),然后再将从父亲到根的路径都加上sum。

代码

    #include<bits/stdc++.h>    using namespace std;    template<typename T>    void read(T &x,char ch=getchar())    {        for (x=0;ch<'0'||ch>'9';ch=getchar());        for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());    }    #define MAXN 100010    #define INF 1LL<<60    typedef long long ll;    int T,n,m,ord,sta,opt,u,v,t;    int seq[MAXN],size[MAXN],son[MAXN],fa[MAXN],top[MAXN],deep[MAXN],dfn[MAXN],rdfn[MAXN];    ll w[MAXN],FK;    namespace PT    {        struct Node{            Node *ch[2];            ll mn,add,sum;            void pushup()            {                mn=min(ch[0]->mn,ch[1]->mn)+add;                sum=ch[0]->sum+ch[1]->sum;            }        }*null=new Node;        Node pool[MAXN*400];        Node *tail;        Node *ver[MAXN];        Node *NewNode(Node *f=0)        {            Node *p=tail++;            if (f)            {                p->ch[0]=f->ch[0];p->ch[1]=f->ch[1];                p->mn=f->mn;                p->add=f->add;                p->sum=f->sum;            }            else                p->ch[0]=p->ch[1]=null;            return p;        }        Node *build(int l,int r)        {            Node *ret=NewNode();            if (l==r)            {                ret->mn=w[seq[l]];                ret->add=0;                ret->sum=0;                return ret;            }            int mid=(l+r)>>1;            ret->ch[0]=build(l,mid);            ret->ch[1]=build(mid+1,r);            ret->pushup();            return ret;        }        void init()        {            tail=pool;            null->ch[0]=null->ch[1]=null;            null->mn=INF;            null->sum=0;            null->add=0;            ver[0]=build(1,n);        }        void add(int pos,int l,int r,Node* &now,ll val)        {            now=NewNode(now);            if (l==r)            {                now->sum+=val;                return;            }            int mid=(l+r)>>1;            if (pos<=mid)                add(pos,l,mid,now->ch[0],val);            else                add(pos,mid+1,r,now->ch[1],val);            now->pushup();        }        void Iadd(int L,int R,int l,int r,Node* &now,ll val)        {            now=NewNode(now);            if (L<=l && r<=R)            {                now->add+=val;                now->mn+=val;                return;            }            int mid=(l+r)>>1;            if (L<=mid)                Iadd(L,R,l,mid,now->ch[0],val);            if (R>mid)                Iadd(L,R,mid+1,r,now->ch[1],val);            now->pushup();        }        void clear(int L,int R,int l,int r,ll tag,Node* &now,Node *pre)        {            if (L<=l && r<=R)            {                FK+=now->sum;                now=NewNode(pre);                now->add-=tag;                now->mn-=tag;                return;            }            now=NewNode(now);            int mid=(l+r)>>1;            if (L<=mid)                clear(L,R,l,mid,tag+now->add,now->ch[0],pre->ch[0]);            if (R>mid)                clear(L,R,mid+1,r,tag+now->add,now->ch[1],pre->ch[1]);            now->pushup();        }        int query_mn(int L,int R,int l,int r,Node *now,ll val)        {            if (now->mn >= val) return 0;            if (l==r) return seq[l];            int mid=(l+r)>>1;            if (R>mid)            {                int ret=query_mn(L,R,mid+1,r,now->ch[1],val-now->add);                if (ret) return ret;            }            if (L<=mid)                return query_mn(L,R,l,mid,now->ch[0],val-now->add);            return 0;        }        void debug(int l,int r,Node *now)        {            printf("[%d,%d]:mn=%lld,add=%lld,sum=%lld\n",l,r,now->mn,now->add,now->sum);            if (l==r)                return;            int mid=(l+r)>>1;            debug(l,mid,now->ch[0]);            debug(mid+1,r,now->ch[1]);        }    }    struct edge{        int s,t,next;    }e[MAXN<<1];    int head[MAXN],cnt;    void addedge(int s,int t)    {        e[cnt].s=s;e[cnt].t=t;e[cnt].next=head[s];head[s]=cnt++;        e[cnt].t=s;e[cnt].s=t;e[cnt].next=head[t];head[t]=cnt++;    }    void dfs(int node,int lastfa,int de)    {        fa[node]=lastfa;        deep[node]=de;        size[node]=1;        son[node]=0;        for (int i=head[node];i!=-1;i=e[i].next)            if (e[i].t!=lastfa)            {                dfs(e[i].t,node,de+1);                size[node]+=size[e[i].t];                if (size[e[i].t]>size[son[node]])                    son[node]=e[i].t;            }    }    void dfs2(int node,int lastfa,int tp)    {        top[node]=tp;        dfn[node]=++ord;        seq[ord]=node;        if (son[node])            dfs2(son[node],node,tp);        for (int i=head[node];i!=-1;i=e[i].next)            if (e[i].t!=lastfa && e[i].t!=son[node])                dfs2(e[i].t,node,e[i].t);        rdfn[node]=ord;    }    int get_mn(int sta,int u,ll v)    {        while (u)        {            int ret=PT::query_mn(dfn[top[u]],dfn[u],1,n,PT::ver[sta],v);            if (ret) return ret;            u=fa[top[u]];        }        return 0;    }    void mo_add(int sta,int u,ll v)    {        while (u)        {            PT::Iadd(dfn[top[u]],dfn[u],1,n,PT::ver[sta],v);            u=fa[top[u]];        }        return;    }    int main()    {        read(T);        while (T--)        {            read(n),read(m);n++;            memset(head,0xff,sizeof(head));            cnt=0;            for (int i=2;i<=n;i++)            {                read(u);u++;                addedge(i,u);                read(w[i]);            }            w[1]=INF;            dfs(1,0,1);            ord=0;            dfs2(1,1,1);            PT::init();            for (int i=1;i<=m;i++)            {                read(sta),read(opt),read(u);u++;                if (opt==1)                {                    read(v);                    t=get_mn(sta,u,v);                    printf("%d\n",max(0,t-1));                    if (t)                    {                        PT::ver[i]=PT::ver[sta];                        FK=0;                        PT::clear(dfn[t],rdfn[t],1,n,0,PT::ver[i],PT::ver[0]);                        mo_add(i,fa[t],FK);                    }                    else                    {                        PT::ver[i]=PT::ver[sta];                        PT::add(dfn[u],1,n,PT::ver[i],v);                        mo_add(i,u,-v);                    }                }                else                {                    PT::ver[i]=PT::ver[sta];                    FK=0;                    PT::clear(dfn[u],rdfn[u],1,n,0,PT::ver[i],PT::ver[0]);                    printf("%lld\n",FK);                    mo_add(i,fa[u],FK);                }            }        }        return 0;    }   

Saboteur (Challenge)

题意简述

给你一个图,让你删除某些点,使得剩下的点形成一棵树。
最小化删除权值和。

数据范围

1n104
1m5×104
子任务:
1.n20
2.n40
3.n=m
4.mn+3
5.完全图
6.轮子图
7.随机图

思路

这题甩锅给同学了,代码就不发了……
子任务1暴力,子任务3基环树DP一下,子任务4缩一缩点,子任务5保留两个权值最大的,子任务6两种情况,中间点删了就贪心,不删就DP一下。
子任务7
随机一个加点顺序,如果不成环就加,最后选权值最大的树。
多次随机,贪心优化。
子任务2用随机跑了。
被日本min_25踩了…代码1千行…
OI选手和人家完全没法比啊……

原创粉丝点击