西南民族大学 春季 2023 训练赛 4
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;
}