Educational Codeforces Round 123
A. Doors and Keys
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve() {
string s;
cin >> s;
map<char,int> pos;
for( int i = 0 ; i < 6 ; i ++ )
pos[s[i]] = i;
if( pos['r'] < pos['R'] and pos['g'] < pos['G'] and pos['b'] < pos['B'] )
cout << "YES\n";
else
cout << "NO\n";
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
B. Anti-Fibonacci Permutation
暴力枚举前两位,暴搜后面的。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 55;
array<int, N> a, vis;
int n , cnt;
void dfs( int i ){
if( cnt == n ) return;
if( i == n+1 ){
for( int i = 1 ; i <= n ; i++ )
cout << a[i] << " ";
cout << "\n";
cnt ++;
return ;
}
for( int j = 1 ; j <= n ; j ++ ){
if( vis[j] or j == a[i-1] + a[i-2] ) continue;
a[i] = j , vis[j] = 1;
dfs( i + 1 );
vis[j] = 0;
}
return ;
}
void solve() {
cin >> n , cnt = 0;
fill(vis.begin(), vis.end(), 0);
for (a[1] = 1; a[1] <= n and cnt != n ; a[1]++)
for (a[2] = 1; a[2] <= n and cnt != n ; a[2]++)
if (a[1] != a[2])
vis[a[1]] = vis[a[2]] = 1, dfs(3), vis[a[1]] = vis[a[2]] = 0;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
C. Increase Subarray Sums
\(f[i][j]\)表示前\(i\)位加了\(j\)个\(x\)的最大值。
因为题目要求了连续子区间,所以转移只有两类,一类是自己做起点,另一类是从前一个转移过来。
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve() {
int n , x;
cin >> n >> x;
vector<int> a(n+1) , res(n+1);
for( int i = 1 ; i <= n ; i ++ ) cin >> a[i];
vector<vector<int>> f( n+1 , vector<int>(n+1 , INT_MIN));
for( int i = 1 ; i <= n ; i ++ ){
for( int j = 0 ; j <= n ; j ++ ){
f[i][j] = max( a[i] , f[i-1][j] + a[i] );
if( j > 0 ) f[i][j] = max( { f[i][j] , a[i] + x , f[i-1][j-1] + a[i] + x } );
f[i][j] = max( f[i][j] , 0ll );
res[j] = max( res[j] , f[i][j] );
}
}
for( auto i : res )
cout << i << " ";
cout << "\n";
return ;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
D. Cross Coloring
每一行,每一列只有最后一次染色有效,所以我们倒序来做。
维护每一行每一列是否被染色。并且如果所有的行或列都被染色了,就不能继续染了。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
const int N = 2e5 + 5;
array<int, N> x, y, r, c;
void solve() {
int n, m, k, q;
cin >> n >> m >> k >> q;
fill(x.begin(), x.end(), 0);
fill(y.begin(), y.end(), 0);
for (int i = 1; i <= q; i++) cin >> r[i] >> c[i];
int res = 1;
for (int i = q, cntX = 0, cntY = 0; i >= 1; i--) {
if (cntX == n or cntY == m or (x[r[i]] + y[c[i]] == 2))
continue;
if (x[r[i]] == 0)
x[r[i]] = 1, cntX++;
if (y[c[i]] == 0)
y[c[i]] = 1, cntY++;
res = res * k % mod;
}
cout << res << "\n";
return;
}
int32_t main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--) solve();
return 0;
}
E. Expand the Path
这道题我认为写的最好的就是官解。
能够被访问的单元格一在下两条路径所形成的空间内:
- 第一个
R
重复次数最多,然后最后一个D
重复次数最多; - 第一个
D
重复次数最多,然后最后一个R
重复次数最多。
这点其实还是比较好想的,官解大部分篇幅就是在证明这一点,我们直接跳过就好了。
求解中间部分的面积是本题的难点。实际上我们可以知道的是空的部分一定是左上角和右下角。我们考虑求出这两部分的面积即可。
对于左上角,我们从下往上一行一行的看,当前行空了\(y\)列。我们倒序看操作数组,如果s[i]=R
,则y++
,否则会向上移动一行,此时我们要把y
累加到答案中去。只要模拟这个过程就可以算出左上角的面积。
对于右下角,我们翻转原序列统计过程就和上一步完全相同。
官解最妙其实是写法,不需要真的去扩展数组,
这里看到了,其实第一个\(R\)的目的是为了把其他的操作推到最后后面,所以第一个\(R\)之前对应的\(D\)累加的都是\(n-1\),这也是为什么要倒序处理操作序列。
#include <bits/stdc++.h>
using namespace std;
#define int long long
int calc(string s, int n) {
int l = s.find('R'), ans = l * (n - 1);
for (int i = s.size() - 1, y = 0; i > l; i--) {
if (s[i] == 'D') ans += y;
else y++;
}
return ans;
}
void solve() {
int n;
string s;
cin >> n >> s;
if (s == string(s.size(), s[0])) {
cout << n << "\n";
return;
}
int res = n * n;
res -= calc(s, n);
for (auto &i: s)
i = (i == 'R' ? 'D' : 'R');
res -= calc(s, n);
cout << res << "\n";
return;
}
int32_t main() {
ios::sync_with_stdio(0), cin.tie(0);
int t;
for (cin >> t; t; t--)
solve();
return 0;
}