2022“杭电杯”中国大学生算法设计超级联赛签到题5题

Posted 小哈里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022“杭电杯”中国大学生算法设计超级联赛签到题5题相关的知识,希望对你有一定的参考价值。

Solved Problem ID Title Ratio (Accepted / Submitted)
1001 Multiply 2 Divide 2 4.23% (28/662)
1002 Hack of Multiply 2 Divide 2 2.51% (34/1357)
1003 Find the Number of Paths 20.00% (4/20)
1004 Yet Another Easy Permutation Count Problem 24.00% (6/25)
1005 Yet Another Easy Function Sum Problem 3.47% (14/403)
1006 Maex 29.17% (890/3051)
1007 Shinobu loves trip 11.93% (330/2765)
1008 Shinobu Loves Segment Tree 60.58% (209/345)
1009 Map 19.73% (448/2271)
1010 Planar graph 33.05% (546/1652)
1011 Find different 61.94% (96/155)
1012 Loop 32.23% (718/2228)

文章目录

6.Maex

Maex
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/131072 K (Java/Others)
Total Submission(s): 261 Accepted Submission(s): 112

Problem Description
You are given a rooted tree consisting of n vertices numbered from 1 to n, and the root is vertex 1.

Vertex i has a natural number weight ai, and no two different vertexes have the same weight.

Define bu=MEX x \\space | \\space \\exists v \\in subtree\\left( u \\right), x = a_v$. Unfortunately,a_iarenotgiven.Pleasefindoutthemaximumpossible\\sum_i=1^nb_i.The\\textbfMEX$ of a set is the minimum non-negative integer that doesn’t belong to the set.

Input
The first line contains one integer T(1≤T≤10), indicating the number of test cases.

For each test case:

The first line contains one integer n(1≤n≤5⋅105), indicating the number of nodes.

In the following n−1 lines, each line contains two interger u,v(1≤u,v≤n), indicating an edge (u,v) of the tree.

A guarantee is that forming trees.

Output
For each test case:
One line with an integer, indicating the maximum possible ∑ni=1bi.

Sample Input
3
5
1 2
3 2
1 5
4 1
3
1 2
2 3
1

Sample Output
8
6
1

Source
2022“杭电杯”中国大学生算法设计超级联赛(6)

题意:

  • 给出一颗n个点的有根树(根为1),每个节点有一个自然数(>=0)的权值ai,并且没有两个不同的顶点具有相同的权值。
  • 现在定义节点u的第二权值bi,首先令节点u的子树中的所有节点(包含u本身)ai权值构成集合MEX,bi表示的是不在集合MEX中的最小非负整数。(比如集合2,3,4,就是0。 比如0,1,2,3,就是4)。
  • 现在要求最大化整棵树所有bi的和,求这个和的值。

思路:

  • 考虑某个节点u,他对应的集合中必须有值0才有意义,不然,最小非负整数肯定就是0了。
  • 因为必须两两不同,所以0肯定只有一个。假设如果0放在任何一个非叶子节点,0的所有子节点bi值都是0,所以0肯定是叶子。那么不在0所在的链上的bi值都是0。所以答案肯定是一条链上的bi值相加。
  • 再考虑最大化这条链上的bi值,对于一个节点u能取到的最大的bi值,肯定是他对应的集合大小跟子树大小一样,然后按照(0,1,2,3,4,)这样排列,他才能取到5,不然断掉了就没有意义了,因此肯定是走子树最大的那条边
  • 那么只要一遍dfs预处理出所有节点子树的大小,然后再dfs一遍,令f[u] = max(f[v])+siz[u]的转移即可。
  • 注意ios不能和getchar,scanf,readint一起用, res开个longlong。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
vector<int>G[maxn];
long long siz[maxn];
long long res = 0;
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)

void dfs(int u , int fa)
    siz[u]++;
    for(int v : G[u])
        if(v==fa)continue;
        dfs(v,u);
        siz[u] += siz[v];
    
    return ;

void dfs2(int u, int fa, long long ans)
    res = max(res, ans);
    for(int v : G[u])
        if(v==fa)continue;
        dfs2(v, u, ans+siz[u]);
    


int main()
    IOS;
    int T;  cin>>T;
    while(T--)
        int n;  cin>>n;
        for(int i = 0; i <= n; i++)
            G[i].clear();
            siz[i] = 0;
        
        for(int i = 1; i < n ;i++)
            int u, v;  cin>>u>>v;
            G[u].push_back(v);
            G[v].push_back(u);
        
        res = 0;
        dfs(1,0);
        dfs2(1,0,0);
        cout<<res+1<<"\\n";//叶节点0没有子节点,但是有非负值1,最后加上
    
    return 0;



12.Loop

Loop
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 224 Accepted Submission(s): 113

Problem Description
You are given an array a of length n. You must perform exactly k times operations.

For each operation,

∙ First, you select two integers l,r (1≤l≤r≤n),

∙ Second, change a to b, satisfy :

∘ For each i (1≤i<l) , bi=ai;

∘ For each i (l≤i<r) , bi=ai+1;

∘ br=al

∘ For each i (r<i≤n) , bi=ai;

Find the lexicographically largest possible array after k times operations.

Array x is lexicographically greater than array y if there exists an index i ( 1≤i≤n ) such that xi > yi and for every j(1≤j<i), xj=yj.

Input
The first line of the input contains one integer T (1≤T≤100 ) — the number of test cases. Then T test cases follow.

The first line of the test case contains two integers n,k (1≤n,k≤300000)

The second line of the test case contains n integers a1,a2,…,an(1≤ai≤300000)

The sum of n over all testcases doesn’t exceed 106.

The sum of k over all testcases doesn’t exceed 106.

Output
For each testcase,one line contains n integers ,a1,a2,…,an — the lexicographically largest possible array after k times operations.

Don‘t have spaces at the end of the line

Sample Input
2
7 3
1 4 2 1 4 2 4
5 2
4 3 5 4 5

Sample Output
4 4 2 4 2 1 1
5 4 5 4 3

Source
2022“杭电杯”中国大学生算法设计超级联赛(6)

题意:

  • 给出一个长为n的数组(3e5),可以进行k次(3e5)操作。
  • 每次操作可以选一个区间[l,r],让这个区间的a[l]放到a[r]的位置,其他数全部往前移动一格。
  • 求最后这个数组的字典序最大是多少,输出新数组。

思路:

  • 考虑一次操作,我们会贪心的从头往后找到第一个a[i]<a[i+1],即递增的值,然后把这个值放到后面第一个小于a[i]的数前面。于是我写了一个基于链表的暴力TLE了。
  • 考虑优化:注意到每次操作本质是将一个元素拿出,然后把后面所有元素往前移,最后再把拿出的元素插入到拿出位置的后面的某个位置。所以k次操作可以先弹出k个元素,最后再插入回去(不会跟原数组产生影响,因为即便后面第一个小于a[i]的数也被弹出去了,最后归并的时候堆里从大到小往外拿,还是会放到a[i]后面去的)。
  • 从前往后k次遇到a[i]<a[i+1]就把a[i]放入堆中,最后将剩余的数组与堆中的元素做一次归并操作即可(对应放到第一个小于a[i]的数的前面)。
//1012 - priority_queue & AC
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
int a[maxn], b[maxn], c[maxn];

int main()
    ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
    int T;  cin>>T;
    while(T--)
        int n, k;  cin>>n>>k;
        for(int i = 1; i <= n; i++)cin>>a[i];
        priority_queue<int>q; //默认大根堆
        int cnt = 0;
        for(int i = 1; i <= n; i++)
            while(cnt && b[cnt]<a[i] && k) //a[i-1]<a[i]
                q.push(b[cnt]); //a[i-1]
                k--;
                cnt--;
            
            b[++cnt] = a[i]; //维护剩余数组
        
        //归并
        int num = 0, t = 1;
        for(int i = 1; i <= n; i++)
            if(t > cnt)
                c[++num] = q.top();  q.pop();
            else if(q.size()==0)
                c[++num] = b[t];  t++;
            else
                if(q.top()>b[t])
                    c[++num] = q.top();  q.pop();
                else
                    c[++num] = b[t];  t++;
                
            
        
        for(int i = 1; i <= n; i++)
            cout<<c[i]<<" \\n"[i==n];
        
    
    return 0;



//1012 - list & TLE
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5+100;
#define IOS ios::sync_with_stdio(0), cin.tie(0),cout.tie(0)
int a[maxn];
// void Print(auto first, auto last)
//     for (; first != last; ++first)
//         cout << *first << " ";
//     cout << endl;
// 
void Print2(auto first, auto last)
    last--;  last--;
    for (; first != last; ++first)
        cout << *first << " ";
    cout<< (*last)<<"\\n";


int main()
    IOS;
    int T;  cin>>T;
    while(T--)
        int n, k;  cin>>n>>k;
        for(int i = 1; i <= n; i++)
            cin>>a[i];
        
        a[n+1] = -1;
        n++;
        list<int>lst(a+1,a+n+1);
        // Print(lst.begin(),lst.end());
        int nk = 0;
        for(auto i = lst.begin(); ; )
            auto x = i, y = i; y++;
            if((*i) == -1)break;
            if((*x) < (*y))
                //找到第一个<x的位置cur
                auto cur = y;
                while((*cur) >= (*x))cur++;
                
                //在cur前面插入x
                lst.insert(cur,1,(*x));
                lst.erase(i);
                i = y;
                if(i!=lst.begin())i--;
                nk++;
                // Print(lst.begin(),lst.end());
                if(nk==k)break;
            else
                i++;
            
        
        Print2(lst.begin(),lst.end());
    
    return 0;



10.Planar graph

Planar graph
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/262144 K (Java/Others)
Total Submission(s): 289 Accepted Submission(s): 112

Problem Description
We say an undirected graph is a planar graph, if it exists a way to draw it on a planar, such that no two edges have intersection except the endpoint. For example, the graph below is a planar graph:

But this graph below is not a planar graph, since it can be proved that no matter how to draw this graph on a planar, at least two edges have intersection which is not an endpoint:

For a planar graph, it has some areas separated by edges. For example, the planar graph below has 4 areas (Note that the area 1 is the infinite planar outside):

Give you a planar graph with n vertices and m edges. Each area sets a country. You are the designer and you want to build some tunnels on the edges such that: From one city, you can travel to any other city by going through some tunnels or passing some cities(i.e. you can’t cross one edge unless it sets a tunnel). For example, for the graph above, you can build tunnels like this:

In the picture above, you can travel from city 2 to city 3 by going through tunnel 1, passing the city 1, then going through tunnel 3, passing the city 4, finally going through tunnel 2, and you can arrive to city 3. You can check that from any city you can travel to any other city.

You want the number of tunnels as small as possible. Print the minimum number of tunnels and the ID of edges you build tunnel on.

Input
The first line contains one integer T(1≤T≤15), described the number of test cases.

For each test case:

The first line contains two integers n,m(1≤n≤105,0≤m≤2×105) separated by a space, described the number of vertices and edges.

Next m lines, the i-th line contains two integers u,v(1≤u,v≤n), separated by a space, described the endpoint of the i-th edge. The ID of the i-th edge is i.

It is guaranteed that the given graph is a planar graph. But this graph may have self-loop, parallel edge and the graph may not connected.

Output
The output contains 2T lines.

For each test case:

The first line contains one integer f, described the minimum number of tunnels you have to build.

The second lines contains f integers separated by spaces, the i-th integer described the ID of edges the i-th tunnel built on.

If for a fixed minimum number of tunnels, it has many ways to build the tunnels, print the lexicographically smallest answer.

Sample Input
1
5 7
1 1
1 2
1 3
3 4
3 4
2 4
2 5

Sample Output
3
1 2 4

Source
2022“杭电杯”中国大学生算法设计超级联赛(6)

题意:

  • 给出一张n(1e5)个点m(2e5)条边的无向图,这个图有自环和重边
    并且这个图是平面图(即它存在一种在平面上绘制它的方法,这种画法它的点除了端点之外没有两条边有交点,即所有的边都不会相交。)
  • 按照平面图画法画出来后,这张图把平面分成了若干个面积区域,现在要求我们删掉最少的边让你可以从任意一个区域到达其他所有的区域,求删掉哪些边,有多种方案时输出边的字典序最小的。

思路:

  • 一开始的想法是特判掉自环和重边的情况,剩下一个普通图,然后跑tarjan求边双联通分量和桥,找有多少环,然后每个环选条字典序最小的边更新到答案上去。但是写挂了。(不知道是代码还是思路)
  • 后来猜想,既然每个连通分量都不含圈,这个图删掉边最后的样子应该大概可能是一棵树(题目说图不连通那就好几棵树嘛),,,然后问题就变成了求字典序最大的生成树嘛(把不在生成树中的边都去掉,去掉的边要编号尽量小,那么生成树的边就编号尽量大)。
  • 不确定对不对,但是反正很好敲,于是Kruskal硬水上去,直接就过了。值得一提的是PE了好几发,行末需要有空格没空格PE也是醉了,还有换行什么的(
  • 官方证明(平面图欧拉定理)
//1010
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6+10;

int fa[maxn+10];
void init(int n)for(int i = 1; i <= n; i++)fa[i]=i;
int find(int x)return x==fa[x]?x:fa[x]=find(fa[x]);
void merge(int x, int y)x=find(x);y=find(y);if(x!=y)fa[x]=y;
int count(int n)int cnt=0; for(int i = 1; i <= n; i++)if(fa[i]==i)cnt++;return cnt;

struct edge int u, v, w;e[maxn];
bool cmp(edge a, edge b)return a.w>b.w; 

int main()
    ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
    int T;  cin>>T;
    while(T--)
        int n, m;  cin>>n>>m;
        init(n+1);
        for(int i = 1; i <= m; i++)
            cin>>e[i].u>>e[i].v;  e[i].w = i;
        
        sort(e+1,e+m+1,cmp);
        vector<int>ans(m+1, 0);
        int res = 0;  //Kruskal
        for(int j = 1; j <= m; j++)
            int x = find(e[j].u), y = find(e[j].v);
            if(x != y)
                merge(x,y);
                ans[e[j].w] = 1;
                res++;
            
        
        cout<<m-res<<'\\n';  //不在生成树中的边
        vector<int>vc;
        for(int i = 1; i <= m; i++)
            if(!ans[i])cout<<i<<" ";
        
        cout<<"\\n";
    
    return 0;




9.Map

Map
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 524288/262144 K (Java/Others)
Total Submission(s): 328 Accepted Submission(s): 119
Special Judge

Problem Description
Sakuyalove has a large world map M and a small world map m. Both of the them are in the shape of rectangle. The small map m is compressed from the large map M. If the length of M is a and the width of M is b, then the length of m is ka and the width of m is kb, where 0<k<1. Now Sakuyalove puts the small map m on the large map M such that the small map is completely within the big map (including boundaries). She was surprised to find out that no matter how she places the small map, there always exists exactly one point P represents the same place in small map and large map (For example, in the following pictures, the location of the pin on both maps represents Tokyo, Japan). Sakuyalove wants to find out this point P. Please help her.

Input
The first line contains one integer T(1≤T≤105), described the number of test cases.

Each test case contains eight lines. Each line has two integers x,y(−103≤x,y≤103) separated by one space.

The first four lines are the coordinates of the upper left corner, the upper right corner, the lower right corner and the lower left corner of M.

The last four lines are the coordinates of the upper left corner, the upper right corner, the lower right corner and the lower left corner of m.

It is guaranteed that m is within M, both of the them are in the shape of rectangle, and m is compressed from M.

Please note that the upper left corner, the upper right corner, the lower right corner and the lower left corner of m and M are one-to-one corresponding. For example, in the picture of Hint below, the correspondence of points is A−a, B−b, C−c, D−d. But A−c, B−d, C−a, D−b is not allowed.

Output
Your output should contains T lines. Each line contains two real numbers x,y separated by one space, represents the coordinates of the point P. Your absolute error should not exceed 10−6.

Sample Input
1
0 5
15 5
15 0
0 0
3 2
9 5
10 3
4 0

Sample Output
6.000000 2.000000

Hint
In the first example, the picture is like this:

Source
2022“杭电杯”中国大学生算法设计超级联赛(6)

题意:

  • 给出8个点的坐标,分别是一个大矩形和一个小矩形的四个点。保证这个小矩形落在大矩形的内部,位置随意。
  • 然后这个大矩形是一张大地图,小矩形是小地图,等比例缩放,求图中某个点在大地图和小地图中表示的位置是一样的,即对应的长宽比例相同,输出这个点的坐标。

思路:

  • 直观的想法就是二分点的坐标,然后求在大矩形和小矩形中对应的长宽比例,判断是多了还是少了,然后再去移动。根据小矩形平行,垂直,斜放三种情况分类讨论,每次直线相交算出距离,比例等数据,然后二分点。或者找单峰函数,三分大概也可以。但是又又又写挂了(
  • 最后是巴拿赫不动点定理,结论题,长见识了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

LL X[5], Y[5], x[5], y[5];
LL cross(LL a1, LL a2, LL a3, LL a4)return a1 * a4 - a2 * a3;

int main()
    ios::sync_with_stdio(0)2022“杭电杯”中国大学生算法设计超级联赛签到题5题

2022“杭电杯”中国大学生算法设计超级联赛签到题4题

2022“杭电杯”中国大学生算法设计超级联赛签到题3题

2022“杭电杯”中国大学生算法设计超级联赛签到题5题

2022“杭电杯”中国大学生算法设计超级联赛签到题5题

2022“杭电杯”中国大学生算法设计超级联赛签到题5题