西南民族大学 春季 2023 训练赛 4

发布时间 2023-04-05 15:48:05作者: PHarr

A-小石的图形

#include<bits/stdc++.h>

using namespace std;

const double pi = 3.1415926;

int32_t main() {
    double n , r;
    cin >> n;
    r = n / pi;
    printf("%.3lf" , pi * 0.5 * r * r );
    return 0;
}

B-植树造林

#include<bits/stdc++.h>

using namespace std;

int32_t main() {
    int n;
    cin >> n;
    if( n & 1 ) cout << "1\n";
    else cout << "2\n";
    return 0;
}

C-Forsaken给学生分组

#include<bits/stdc++.h>

using namespace std;

#define int long long 

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

int32_t main() {
    int n = read() , k = read() , x = 0 , y = 0;
    vector<int> a(n);
    for( int &i : a ) i = read();
    sort(a.begin(),a.end());
    for( int i = 0 , t = k ; t ; t -- , i ++ ) y += a[i];
    for( int i = n-1 , t = k ; t ; t -- , i -- ) x += a[i];
    cout << x - y << "\n";
    return 0;
}

D-分数的运算

#include<bits/stdc++.h>

using namespace std;

#define int long long

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

int32_t main() {
    int a, b, c, d, x, y, t;
    cin >> a >> b >> c >> d;
    if (b < 0) a = -a, b = -b;
    if (d < 0) c = -c, d = -d;
    t = lcm(b, d);
    a *= t / b, c *= t / d, b = d = t;
    x = a + c, y = d;
    if (x == 0) cout << "0 0\n";
    else {
        t = abs(gcd(x, y)), x /= t, y /= t;
        cout << x << " " << y << "\n";
    }
    x = a - c, y = d;
    if (x == 0) cout << "0 0\n";
    else {
        t = abs(gcd(x, y)), x /= t, y /= t;
        cout << x << " " << y << "\n";
    }
    x = a * c, y = b * d;
    if (x == 0) cout << "0 0\n";
    else {
        t = abs(gcd(x, y)), x /= t, y /= t;
        cout << x << " " << y << "\n";
    }
    x = a * d, y = b * c;
    if( y < 0 ) x = -x , y = -y;
    if (x == 0) cout << "0 0\n";
    else {
        t = abs(gcd(x, y)), x /= t, y /= t;
        cout << x << " " << y << "\n";
    }

    return 0;
}

E-小y的旅行

保证边\((u,v)\)满足\(u<v\)的情况下,把边按照\(u\)从大到小排序。然后开始加边,并用并查集维护连通性。这样每次加边实际上都是从前先后加边,如果已经联通的情况下在加边就一定会形成一个环,如果\(u<k\)那么这条边就不能要。

#include<bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}
vector<int> fa;
int getfa( int x ){
    if( fa[x] < 0 ) return x;
    return fa[x] = getfa(fa[x]);
}

int32_t main() {
    int n = read(), m = read(), k = read(), res = 0;
    vector<pair<int, int>> e(m);
    for (auto &[u, v]: e) {
        u = read(), v = read();
        if (u > v) swap(u, v);
    }
    sort( e.begin() , e.end() );
    reverse( e.begin() , e.end() );
    fa = vector<int>( n+1 , -1 ) , fa[0] = 0;
    for( auto [ u , v ] : e ){
        int x = getfa(u) , y = getfa(v);
        if( x > y ) swap( x , y );
        if( x != y ) fa[y] = x;
        else if( x <= k ) res ++;
    }
    cout << res;
    return 0;
}

F-小L的数列

首先最朴素的做法肯定是

sort(a.begin(), a.end());
for (int i = 1; i <= n; i++) {
    f[i] = 1;
    for (int j = 1; j < i; j++)
        if (gcd(a[i], a[j]) > 2) f[i] = max(f[i], f[j] + 1);
}

这样的做法是\(O(n^2)\)的。然后\(gcd(a_i,a_j)>1\),说明\(a_i,a_j\)必有至少一个公共质因子。

定义\(f[i]\)表示最后一个数的质因子包含\(i\)的最长好的序列。那么此时我们的枚举就只需要枚举质因子即可。

#include<bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

void solve() {
    int n = read() , res = 0;
    vector<int>a(n);
    for (int &i: a) i = read();
    sort(a.begin(), a.end());
    vector<int> f( a.back()+1 );
    for( auto i : a ){
        int t = i , cnt = 0;
        vector<int> p;
        for( int j = 2 ; j * j <= t && t != 1 ; j ++ ){
            if( t % j ) continue;
            p.push_back(j);
            while( t % j == 0 ) t /= j;
        }
        if( t != 1 ) p.push_back(t);
        for( auto j : p ) cnt = max( cnt , f[j] );
        cnt ++;
        for( auto j : p ) f[j] = cnt;
        res =max( res ,cnt);
    }
    cout << res << "\n";
    return;
}

int32_t main() {
    for (int t = read(); t; t--)
        solve();
    return 0;
}

G-小L的编辑器

直接模拟就好了

#include<bits/stdc++.h>

using namespace std;

int32_t main() {
    int n;
    string s , t;
    cin >> s >> t;
    n = s.size();
    list<char> ans;
    auto pos = ans.begin();
    for( int i = 0 ; i < n ; i ++ ){
        ans.insert( pos , s[i] );
        if( t[i] == 'L' ) pos --;
    }
    for( auto c : ans )
        cout << c;

    return 0;
}

H-1408

\(f[i][j]\)为编号前\(i\)的白球和前\(j\)的黑球的最小价值。那么\(f[i+1][j] = \min( f[i+1][j] , f[i][j] + v)\) 其中\(v\)表示把编号\(i+1\)的白球移动到\(i+j+1\)的位置的代价,代价实际上就是两个位置的差值。最初的时候白球\(i+1\)\(pos\)如果前个\(i\)白球和前\(j\)个黑球共有\(k\)个在\(pos\)之后,那么\(pos\)就要向后移动\(pos\)位,即\(pos = pos + k\)。黑球同理。

#include<bits/stdc++.h>

using namespace std;

const int N = 2005;
char col[N*2];
int id[N*2];// 位置 i 的小球的颜色和编号
int posW[N], posB[N]; // 标号 i 的 W/B 小球的位置
int sufW[N*2][N], sufB[N*2][N]; // 位置 i 之后有多少个编号小于等于 j 的 W/B 小球
int f[N][N]; // 编号前 i 的 W 球, 前 j 的 B 球的有序最小代价


int32_t main() {
    int n;
    cin >> n;
    for( int i = 1 ; i <= n*2 ; i ++ ){
        cin >> col[i] >> id[i];
        if( col[i] == 'W' ) posW[ id[i] ] = i;
        else posB[ id[i] ] = i;
    }
    for( int i = 1 ; i <= 2*n ; i ++ ){
        if( col[i] == 'W' ){
            for( int j = id[i] ; j <= n+1 ; j ++ )
                sufW[i][j] ++;
        } else{
            for( int j = id[i]; j <= n+1 ; j ++ )
                sufB[i][j] ++;
        }
    }
    for( int i = n*2 ; i >= 1 ; i -- )
        for( int j = n ; j >= 1 ; j -- )
            sufW[i][j] += sufW[i+1][j] , sufB[i][j] += sufB[i+1][j];
    fill( f[0] , f[0] + N*N , INT_MAX );
    f[0][0] = 0;
    for( int i = 0 ; i <= n ; i ++ ){
        for( int j = 0 ; j <= n ; j ++ ){
            int now = i + j + 1;
            if( i < n ){
                int pos = posW[i+1];
                int d = sufW[pos][i] + sufB[pos][j];
                pos += d;
                f[i+1][j] = min( f[i+1][j] , f[i][j] + pos - now );
            }
            if( j < n ){
                int pos = posB[j+1];
                int d = sufW[pos][i] + sufB[pos][j];
                pos += d;
                f[i][j+1] = min( f[i][j+1] , f[i][j] + pos - now );
            }
        }
    }
    cout << f[n][n] << "\n";
    return 0;
}