AtCoder Beginner Contest 225(补题)

Posted 佐鼬Jun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 225(补题)相关的知识,希望对你有一定的参考价值。

D - Play Train

链接: link.

题意:

N N N个或者分离的火车头,现在有 Q Q Q次操作,每次操作有 3 3 3种类型, 1. x 1.x 1.x y y y代表把 x x x车的尾部和 y y y车的头部连接起来
2. x 2.x 2.x y y y代表把 x x x车的尾部和 y y y车的头部分离开
3. x 3.x 3.x代表 输出与 x x x车连接的所有车,输出个数并从头到尾输出各个车的编号

思路:

用非路径压缩版并查集就可以解决这个问题,直接按照输入的操作,分别实现并查集的合并、分离,并按照顺序输出并查集元素。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 10;
int fa[N];
int son[N];
int n, q;
int find(int x) 
    if (x != fa[x]) return find(fa[x]);
    return x;


void Union(int a, int b) 
    fa[b] = a;
    son[a] = b;


void del(int a, int b) 
    fa[b] = b;
    son[a] = a;


void print(int x) 
    int st = find(x);
    vector<int> res;
    while (son[st] != st) 
        res.push_back(st);
        st = son[st];
    
    res.push_back(st);
    cout << res.size() << " ";
    for (int i = 0; i < res.size(); i++) 
        cout << res[i] << " ";
    
    puts("");

int main() 
    cin >> n >> q;
    for (int i = 0; i < N; i++) 
        fa[i] = i;
        son[i] = i;
    
    while (q--) 
        int op, x, y;
        scanf("%d%d", &op, &x);
        if (op == 1) 
            scanf("%d", &y);
            Union(x, y);
        
        if (op == 2) 
            scanf("%d", &y);
            del(x, y);
        
        if (op == 3) 
            print(x);
        
    

E - 7

链接: link.

题意:

在二维坐标轴中,给 N N N个坐标,在二维坐标系中有 N N N 7 7 7, 7 7 7是由坐标 ( x i , y i ) (x_i,y_i) (xi,yi) ( x i − 1 , y i ) (x_i-1,y_i) (xi1,yi)构成的线段和 ( x i , y i ) (x_i,y_i) (xi,yi) ( x i , y i − 1 ) (x_i,y_i-1) (xi,yi1)g构成的线段组成,如果一个 7 7 7与坐标原点形成的四边形,与其他的四边形没有发生冲突(即没有交点),就说明 7 7 7是好的,现在问有多少个好 7 7 7

思路:

对于一个 ( x i , y i ) (x_i,y_i) (xi,yi)考虑与 ( x i − 1 , y i ) (x_i-1,y_i) (xi1,yi) ( x i , y i − 1 ) (x_i,y_i-1) (xi,yi1)构成的图形,就是以 ( x i − 1 , y i ) (x_i-1,y_i) (xi1,yi) ( x i , y i − 1 ) (x_i,y_i-1) (xi,yi1)和原点所形成的两条直线所占据的图形,这两条直线的斜率为 k 1 和 k 2 k1和k2 k1k2。如果某条直线与当前这个图形的两条直线有交点,那就说明这条直线的斜率在 [ k 1 , k 2 ] [k1,k2] [k1,k2]之间。所以说每个 7 7 7所占有的斜率 [ k 1 , k 2 ] [k1,k2] [k1,k2],可以看作在数轴上占据了这段这段区间,现在问题转换为最大不相交区间个数(不包括端点)
也可以通过极角排序来实现,一样的原理。
注:因精度问题不开long double 过不了

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;

int main() 
    int n;
    cin >> n;
    vector<pair<long double, long double> > s(n);
    for (int i = 0; i < n; i++) 
        ld x, y;
        cin >> x >> y;
        s[i].second = atan2(y - 1, x);
        s[i].first = atan2(y, x - 1);
    

    sort(s.begin(), s.end());

    ld now = 0.0;
    ll res = 0;

    for (int i = 0; i < n; i++) 
        if (now <= s[i].second) 
            res++;
            now = s[i].first;
        
    
    cout << res << endl;

F - String Cards

链接: link.

题意:

给定 N N N个字符串,现在让你选出 K K K个字符串,可以以任意顺序拼接,现在让你输出拼接后字典序最小的字符串。

思路:

如果此题没有选 K K K个字符串的限制,而是任意拼接然后输出字典序最小,题目就会变成下面这道题
题目链接: link.
链接: link
在没有限制的情况下,就只需要对字符串拼接后的大小来进行排序。即

bool cmp(string a, string b)  return a + b < b + a; 

含义就是排序的后面的子串不管是什么样只要往前连,肯定使连起来的字符串变小,说白了 就是两个字符串 a b ab ab b a ba ba排序,要是 a b ab ab b a ba ba a a a就放 b b b左边。此时排完序后,定义一个 d p dp dp方程
d p ( i , j ) dp(i,j) dp(i,j),代表从字符串 s i , s i + 1 . . . . . . s n s_i,s_i+1......s_n si,si+1......sn中选 j j j个字符串拼接到当前字符串上形成的最小字典序字符串,那么此时
d p ( i , j ) = m i n ( d p ( i + 1 , j ) , s i + d p ( i + 1 , j − 1 ) ) dp(i,j)=min(dp(i+1,j),s_i+dp(i+1,j-1)) dp(i,j)=min(dp(i+1,j),si+dp(i+1,j1))
因为如果我选了 s i s_i si,那么 d p ( i , j ) = s i + d p ( i + 1 , j − 1 ) dp(i,j)=s_i+dp(i+1,j-1) dp(i,j)=si+dp(i+1,j1)
如果我不选 s i s_i si以上是关于AtCoder Beginner Contest 225(补题)的主要内容,如果未能解决你的问题,请参考以下文章