• 2022杭电多校6(总结+补题)


    总结

    这把应该是多校以来打得最差的一把了,开局我和队友1签了1006,又把1012讨论出来之后,就跟队友2看计算几何去了,队友2看了一会提出一个“看上去正确但贼复杂的做法”,然后我就听信了他的谗言开写,写了一个多小时之后发现写挂了,就开始了疯狂debug,最后写好之后发现方法假了,但队友2一直坚持自己是对的(他不知道计算几何做这么多操作会失精度),于是我就陪他一直在这道题上磨到了最后,也没有看其他题,队友1期间也一直在自闭,总的来说,这场的策略问题很大,不应该因为队友的一个思路就一直死做一个题不看其他,也不应该在签完到之后就跑去死磕不熟练的计算几何,一场打完大家心态都崩了。

    题解

    1006 - Maex

    题意:

    给定一棵由从 1 1 1 n n n 编号的 n n n 个顶点组成的有根树,根为顶点 1 1 1 。顶点 i i i 有一个自然数权重 a i a_i ai,并且没有两个不同的顶点具有相同的权重(这个权重由我们自己分配)。定义一个点的 b u = M E X { x   ∣   ∃ v ∈ s u b t r e e ( u ) , x = a v } b_u=MEX\left \{ x \space | \space \exists v \in subtree(u),x=a_v \right \} bu=MEX{x  vsubtree(u),x=av} ,即一个点的 b b b 值等于其子树(包括它自己)所有权重集合的 M E X MEX MEX 值,问 ∑ i = 1 n b i \sum_{i=1}^{n} b_i i=1nbi 的最大值是多少。

    做法:

    M E X MEX MEX 的性质和观察我们可以知道,一个节点的 b i b_i bi 值为其子树中所有节点的个数, ∑ i = 1 n b i \sum_{i=1}^{n} b_i i=1nbi 的值即为一条链中所有节点的 b i b_i bi 值之和

    ,因此我们可以采用树形 d p dp dp 的方法, d p [ u ] dp[u] dp[u] 表示子树 s u b t r e e ( u ) subtree(u) subtree(u) s u m ( b i ) sum(b_i) sum(bi) 能达到的最大值, s o n son son 数组记录 u u u 节点子树节点的个数,那么就有 d p dp dp 方程:

    d p [ u ] = s o n [ u ] + m a x ( d p [ v ] ) ( v ∈ s u b t r e e ( u ) ) dp[u]=son[u]+max(dp[v])(v\in subtree(u)) dp[u]=son[u]+max(dp[v])(vsubtree(u))

    代码:

    /*
     author:wuzx
     */
    
    #include
    #define ll long long
    #define int long long
    #define endl "\n"
    #define P pair<int,int>
    #define f first
    #define s second
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int t;
    int n,m,k;
    signed main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        cin>>t;
        while(t--)
        {
            cin>>n;
            vector<vector<int>> g(n);
            for(int i=1;i<n;i++)
            {
                int u,v;
                cin>>u>>v;
                u--;v--;
                g[u].push_back(v);
                g[v].push_back(u);
            }
            vector<int> dp(n,0);
            function<int(int,int)> dfs = [&](int now,int fr)
            {
                int son=1;
                int ma=0;
                for(int x:g[now])
                {
                    if(x==fr)
                        continue;
                    son+=dfs(x,now);
                    ma=max(ma,dp[x]);
                }
                dp[now]=son+ma;
                return son;
            };
            dfs(0,-1);
            cout<<dp[0]<<endl;
        }   
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    1009 - Map

    题意:

    给你一个长方形以及这个长方形按比例 k ( 0 < k < 1 ) k(0k(0<k<1) 缩小后的小长方形,将两长方形的 A − a   , B − b A-a\space ,B-b Aa ,Bb 相连形成的直线相交于点 P P P ,再将小长方形围绕点 P P P 旋转任意角度,现给出原长方形的四个顶点 A   B   C   D A\space B \space C \space D A B C D 以及旋转后小长方形的四个顶点 a   b   c   d a\space b \space c \space d a b c d ,求点 P P P 的坐标。

    做法:

    我们假设点 P ,由于在长方形中有 A B ⊥ A D AB \perp AD ABAD , 因此可设

    O P ⃗ = O A ⃗ + λ A B ⃗ + μ A D ⃗ \vec{OP}=\vec{OA}+\lambda \vec{AB}+ \mu \vec{AD} OP =OA +λAB +μAD

    其中 λ , μ \lambda,\mu λ,μ 为待定参数,又因为点 P P P 在两个长方形中的对应关系相同,因此又有:

    O P ⃗ = O a ⃗ + λ a b ⃗ + μ a d ⃗ \vec{OP}=\vec{Oa}+\lambda \vec{ab}+ \mu \vec{ad} OP =Oa +λab +μad

    联立上式可得:

    λ ( A B ⃗ − a b ⃗ ) + μ ( A D ⃗ − a d ⃗ ) = O a ⃗ − O A ⃗ \lambda(\vec{AB}-\vec{ab})+\mu(\vec{AD}-\vec{ad})=\vec{Oa}-\vec{OA} λ(AB ab )+μ(AD ad )=Oa OA

    解出 λ , μ \lambda,\mu λ,μ 后带入一式可得 P P P 的坐标

    代码:

    /*
     author:wuzx
     */
    
    #include
    #define ll long long
    #define int long long
    #define endl "\n"
    #define P pair<int,int>
    #define f first
    #define s second
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int t;
    int n,m,k;
    struct point{
        double x,y;
    };
    signed main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        cin>>t;
        int a1,a2,b1,b2,c1,c2,d1,d2;
        point A,B,C,D,a,b,c,d;
        while(t--)
        {
            cin>>a1>>a2>>b1>>b2>>c1>>c2>>d1>>d2;
            A.x=a1;A.y=a2;B.x=b1;B.y=b2;C.x=c1;C.y=c2;D.x=d1;D.y=d2;
            cin>>a1>>a2>>b1>>b2>>c1>>c2>>d1>>d2;
            a.x=a1;a.y=a2;b.x=b1;b.y=b2,c.x=c1;c.y=c2;d.x=d1;d.y=d2;
            double x1=B.x-A.x-b.x+a.x;
            double y1=B.y-A.y-b.y+a.y;
            double x2=D.x-A.x-d.x+a.x;
            double y2=D.y-A.y-d.y+a.y;
            double AA=a.x-A.x;
            double BB=a.y-A.y;
            double u=(BB*x2-AA*y2)/(x2*y1-x1*y2);
            double r=(BB*x1-AA*y1)/(x1*y2-x2*y1);
            cout<<fixed<<setprecision(8)<<A.x+u*(B.x-A.x)+r*(D.x-A.x)<<" "<<
            A.y+u*(B.y-A.y)+r*(D.y-A.y)<<endl;
        } 
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    1010 - Planar graph

    题意:

    给你一个平面图,图中一些边,每条边的编号为题目给出的顺序,问最少要消除那些边,使得原来平面图中的平面全部连通,给出字典序最小的消除边的解。

    做法:

    由于我们要消去一些边使原图中的平面两两连通,我们可知在消去边之后原来的图中不存在环,那么消去边后的图应该是一棵树,又因为我们要给出消去边字典序最小的解,因此我们可以把边的序号作为边权,构造一棵最大生成树,未被使用的边即为字典序最小的要消除的边。

    代码:

    /*
     author:wuzx
     */
    
    #include
    #define ll long long
    #define int long long
    #define endl "\n"
    #define P pair<int,int>
    #define f first
    #define s second
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int t;
    int n,m,k;
    struct dsu{
        const int nn;
        vector<int> fa;
        dsu(int n1):nn(n1),fa(n+1)
        {
            for(int i=0;i<=n;i++)
                fa[i]=i;
        }
        int find(int x)
        {
            return fa[x]==x?x:fa[x]=find(fa[x]);
        }
        void merge(int x,int y)
        {
            int aa=find(x),bb=find(y);
            if(aa!=bb)
                fa[aa]=bb;
        }
    };
    #define tp3 tuple<int,int,int> 
    signed main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        cin>>t;
        while(t--)
        {
            cin>>n>>m;
            dsu ds(n);
            vector<tp3> a;
            for(int i=1;i<=m;i++) 
            {
                int u,v;
                cin>>u>>v;
                a.emplace_back(i,u,v);
            }
            function<bool(tp3,tp3)> cmp = [&](tp3 aa,tp3 bb)
            {
                return get<0>(aa)>get<0>(bb);
            };
            sort(a.begin(),a.end(),cmp);
            vector<int> vis(m+1,0);
            for(int i=0;i<m;i++)
            {
                int u,v,w;
                tie(w,u,v)=a[i];
                if(ds.find(u)!=ds.find(v))
                {
                    ds.merge(u,v);
                    vis[w]=1;
                }
            }
            int ans=count(vis.begin()+1,vis.end(),0);
            
            cout<<ans<<endl;
            for(int i=1;i<=m;i++)
                if(!vis[i])
                    cout<<i<<" ";
            cout<<endl;
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    1012 - Loop

    题意:

    给你一个数组 a a a ,你可以对数组 a a a k k k 次以下操作:

    选定 [ l , r ] [l,r] [l,r] ,将 a [ l , … , r ] a[l,…,r] a[l,,r] 中所有元素向左移动一个单位,移动后 a [ l ] a[l] a[l] a [ r ] a[r] a[r] 的位置上,问:在 k k k 次操作后,输出字典序最大的数组 a a a

    做法:

    考虑贪心做法,每次移动我们都把当前剩余序列中第一个 a [ i ] < a [ i + 1 ] a[i]a[i]<a[i+1] 中第一个 a [ i ] a[i] a[i] 放入优先队列 q q q 中(这里找第一个 a [ i ] < a [ i + 1 ] a[i]a[i]<a[i+1] 使用的是用并查集实现的链表,每次删除当前元素就用前一个元素指向后一个元素),用完 k k k 次操作或没有满足条件的 a [ i ] a[i] a[i] 时,我们开始将优先队列中的数插入回原序列中(也就是将 a [ l ] a[l] a[l] 放到原来 a [ r ] a[r] a[r] 的位置),在原序列中从头开始,如果 a [ i ] < q . t o p ( ) a[i] < q.top() a[i]<q.top() ,则将优先队列的堆首元素插入到 a[i] 前面,否则 i i i++ ,原剩余序列如果遍历完,就按顺序将优先队列中元素放到原序列后方,若优先队列中无元素,就直接把构造好的序列输出即可。

    代码:

    /*
     author:wuzx
     */
    
    #include
    #define ll long long
    // #define int long long
    #define endl "\n"
    #define P pair<int,int>
    #define f first
    #define s second
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int t;
    int n,m,k;
    signed main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        cin>>t;
        while(t--)
        {
            cin>>n>>k;
            vector<int> a(n+1),pre(n+1),bak(n+2);
            for(int i=1;i<=n;i++)
            {
                cin>>a[i];
                pre[i]=i;
                bak[i]=i;
            }
            bak[n+1]=n+1;
            priority_queue<int> q;
            function<int(int)> find1 = [&](int x)
            {
                return pre[x]==x?x:pre[x]=find1(pre[x]);
            };
            function<int(int)> find2 = [&](int x)
            {
                return bak[x]==x?x:bak[x]=find2(bak[x]);
            };
            int idx=1;
            int fst=inf;
            while(k)
            {
                int now=find2(idx);
                if(now==n)
                    break;
                int nxt=find2(now+1);
                if(a[now]<a[nxt])
                {
                    q.push(a[now]);
                    // cout<
                    k--;
                    fst=min(fst,now);
                    int n1=now;
                    bak[now]=nxt;
                    if(find1(now-1)!=0)
                    {
                        pre[find1(now)]=find1(now-1);
                        idx=pre[now];
                    }
                    else
                        idx=bak[now];
                }
                else
                    idx=nxt;
            }
            int now=find2(1);
            vector<int> ans;
            while(now<fst&&now<=n)
            {
                // cout<<"out "<
                ans.push_back(a[now]);
                now=find2(now+1);
            }
            now=find2(now);
            while(!q.empty())
            {
                if(a[now]>=q.top())
                {
                    ans.push_back(a[now]);
                    now=find2(now+1);
                }
                else
                {
                    ans.push_back(q.top());
                    q.pop();
                }
                if(now==n+1)
                    break;
            }
            while(!q.empty())
            {
                ans.push_back(q.top());
                q.pop();
            }
            while(now<=n)
            {
                ans.push_back(a[now]);
                if(now==n)
                    break;
                now=find2(now+1);
            }
            for(int i=0;i<n;i++)
                cout<<ans[i]<<" \n"[i==n-1];
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
  • 相关阅读:
    【CTF机器人】文件头字节查询(Nonebot2+CQHTTP)
    Docker安装并启动Nacos
    低代码是什么意思?低代码平台的技术特点是什么?
    geopandas 通过sjoin进行空间关系连接
    [C++] 小游戏 斗破苍穹 2.2.1至2.11.5所有版本(中) zty出品
    fastapi_No.18_后台应用
    XML解析
    学习之浅谈python如何做接口自动化
    融云:让银行轻松上“云”
    docker中DVWA的安装
  • 原文地址:https://blog.csdn.net/m0_51028279/article/details/126186559